Parece que List<T>
en C # puede hacer todo lo que una matriz puede hacer y más, y también parece tan eficiente en memoria y rendimiento como una matriz.
Entonces, ¿por qué querría usar una matriz?
Obviamente no estoy preguntando sobre casos en los que una API u otra restricción externa (es decir, la función Principal) requiere que use una matriz ... Solo estoy preguntando sobre la creación de nuevas estructuras de datos en mi propio código.
c#
data-types
JoelFan
fuente
fuente
List<T>
is also just as efficient in memory and performance as an array
- um. ¿De dónde sacaste esa idea?var test = new string[5,5]
;)Respuestas:
La misma razón por la que no conduzco un camión cuando voy a trabajar. No uso algo de lo que no usaré las características.
En primer lugar, una matriz es una construcción primitiva, por lo que una matriz es más rápida y más eficiente que una Lista <>, por lo que su argumento no es verdadero. La matriz también está disponible en todas partes y es conocida por los desarrolladores que utilizan diferentes idiomas y plataformas.
La razón más importante por la que uso una matriz en lugar de una Lista <> es para implicar que los datos tienen una longitud fija . Si no voy a agregar o eliminar ningún elemento de esa recopilación de datos, quiero asegurarme de que el tipo refleje eso.
Otra cosa es, digamos, que está implementando una nueva estructura de datos y que ha leído algunos documentos al respecto. Ahora, al implementar algoritmos específicos, no siempre se puede confiar en la implementación de otro tipo de propósito general. Cambia de .NET a Mono e incluso entre diferentes versiones del marco.
Y a veces es más fácil portar un fragmento de código que utiliza una matriz en lugar de un tipo dependiente del marco.
fuente
List<T>
se implementa usando una matriz? Si conoce el recuento de elementos de antemano (que debe saber cuando usa una matriz), puede usar ese conocimiento al inicializar la lista también.Necesita matrices para administrar su colección de estructuras mutables , por supuesto, y qué haríamos sin ellas.
(tenga en cuenta que puede haber algunos casos en los que sea deseable una matriz de estructuras mutables, pero generalmente este comportamiento diferente de estructuras mutables dentro de las matrices frente a otras colecciones es una fuente de errores que deben evitarse)
Más en serio, necesita una matriz si desea pasar un elemento por referencia . es decir
Eso puede ser útil para el código seguro de subprocesos sin bloqueo.
Necesita una matriz si desea inicializar de manera rápida y eficiente su colección de tamaño fijo con el valor predeterminado .
(tenga en cuenta que sería posible implementar un constructor para List que haga lo mismo, es solo que C # no ofrece esta función)
necesita una matriz si quiere copiar eficientemente partes de la colección
(de nuevo, esto es algo que también podría implementarse para List, pero esta característica no existe en c #)
fuente
En raras ocasiones , tendrá un escenario en el que sabe que necesita un número fijo de elementos. Desde una perspectiva de diseño, esto debe evitarse. Si necesita 3 cosas, la naturaleza del negocio significa que muy a menudo necesitará 4 en la próxima versión.
Aún así, cuando este raro escenario realmente ocurre, es útil usar una matriz para hacer cumplir ese invariante de tamaño fijo. Proporciona una señal a otros programadores de que tiene un tamaño fijo y ayuda a evitar el mal uso en el que alguien agrega o elimina un elemento, lo que rompe las expectativas en otras partes del código.
fuente
Su pregunta ya ha sido respondida antes .
No lo es De la pregunta que vinculé:
Las matrices son dos veces más rápidas en ciertos casos importantes. Estoy seguro de que el uso de la memoria también difiere de manera no trivial.
Dado que la premisa principal de su pregunta es derrotada, supongo que esto responde a su pregunta. Además de esto, a veces las matrices son forzadas por Win32 API, o el sombreador de su GPU, o alguna otra biblioteca que no sea DotNet.
Incluso dentro de DotNet, algunos métodos consumen y / o devuelven matrices (como
String.Split
). Lo que significa que ahora debe pagar el costo de las llamadasToList
yToArray
todo el tiempo, o debe conformarse y usar la matriz, posiblemente continuando el ciclo propagándolo a los usuarios pobres de su código.Más preguntas y respuestas sobre Stack Overflow sobre este tema:
List<T>
: ¿Cuándo usar cuál?List<>
?fuente
Además de las razones enumeradas en otras respuestas, el literal de matriz requiere menos caracteres para declarar:
El uso de la matriz en lugar de
List
hace que el código sea un poco más corto y un poco más legible en los casos en que (1) necesita pasar unIEnumerable<T>
literal, o (2) donde otras funcionesList
no importan y necesita usar algunas listas literal.He hecho esto ocasionalmente en pruebas unitarias.
fuente
foreach( var x in new []{ a, b, c ) ) DoStuff( x )
onew []{ a, b, c ).Select( ... )
etc.Esto es estrictamente desde una perspectiva OO.
Si bien no puedo pensar en una razón para pasar solo una matriz, ciertamente puedo ver situaciones en las que una representación de matriz interna de la clase es probablemente la mejor opción.
Si bien existen otras opciones que ofrecen características similares, ninguna parece tan intuitiva como una matriz para problemas relacionados con el procesamiento de permutaciones, anidadas para bucles, representación matricial, mapas de bits y algoritmos de intercalación de datos.
Hay un número considerable de campos científicos que se basan ampliamente en las matemáticas de matriz. (por ejemplo, procesamiento de imágenes, corrección de errores de datos, procesamiento de señales digitales, una gran cantidad de problemas matemáticos aplicados). La mayoría de los algoritmos en esos campos están escritos en términos de uso de matrices / matrices multidimensionales. Por lo tanto, sería más natural implementar los algoritmos tal como se definen en lugar de hacerlos más amigables con el "software" a expensas de perder los vínculos directos con los documentos en los que se basan los algoritmos.
Como dije, en estos casos, probablemente pueda salirse con la suya usando listas, pero eso agrega otra capa de complejidad además de lo que ya son algoritmos complejos.
fuente
Esto realmente se aplica a otros lenguajes que también tienen listas (como Java o Visual Basic). Hay casos en los que necesita usar una matriz porque un método devuelve una matriz en lugar de una Lista.
En un programa real, no creo que se use una matriz muy a menudo, pero a veces sabes que los datos tendrán un tamaño fijo y te gusta la pequeña ganancia de rendimiento que obtienes al usar una matriz. La microoptimización sería una razón válida, como un método que devuelve una lista, o la necesidad de una estructura de datos multidimensional.
fuente
list<T>
wherevector<T>
will work es una idea desastrosamente mala en C / C ++.vector<T> x
compila bien para mí en C . :-)list<T>
. Básicamente, he visto muchos problemas de rendimiento causados por los desarrolladores que solo usan listas por defecto cuando una matriz era una mejor opción.Bueno, encontré un uso para las matrices en un juego que he estado escribiendo. Lo usé para crear un sistema de inventario con un número fijo de ranuras. Esto tuvo varios beneficios:
Pensé que si alguna vez necesitaba "aumentar" el tamaño del inventario, podría hacerlo transfiriendo los elementos antiguos a la nueva matriz, pero dado que el inventario estaba arreglado por el espacio de la pantalla y no tenía necesidad de hacerlo dinámicamente más grande / más pequeño, funcionó bien para el propósito para el que lo estaba usando.
fuente
Si está atravesando todos los elementos de una lista, entonces no, no es necesaria una matriz, la 'selección sin reemplazo' 'siguiente' o arbitraria funcionará bien.
Pero si su algoritmo necesita acceso aleatorio a los elementos de la colección, entonces, sí, es necesaria una matriz.
Esto es algo análogo a "¿es necesario ir?". En un lenguaje moderno razonable no es necesario en absoluto. Pero si elimina las abstracciones, en algún momento, eso es todo lo que está realmente disponible para usted, es decir, la única forma de implementar estas abstracciones es con la característica 'innecesaria'. (Por supuesto, la analogía no es perfecta, no creo que nadie diga que los arreglos son una mala práctica de programación; son fáciles de entender y pensar).
fuente
List<T>
.Compatibilidad heredada.
Todo forma experiencia personal:
Programadores heredados: mi colega usa matrices en todas partes, lo ha hecho durante más de 30 años, la buena suerte cambió de opinión con sus nuevas ideas.
Código heredado: foo (barra de matriz []) seguro de que puede usar una función de lista / vector / colección toarray, pero si no usa ninguna de las características adicionales, es más fácil usar una matriz para empezar, a menudo más legible sin el cambio de tipo.
Jefa heredada: mi jefa era una buena programadora antes de que ella se pusiera en la gerencia hace muchos años y todavía piensa que está al día, "estaba usando matrices" puede finalizar una reunión, explicando lo que una colección puede costarles a todos el almuerzo.
fuente
1) No hay una versión multidimensional de List. Si sus datos tienen más de una dimensión, será muy ineficiente usar listas.
2) Cuando se trata de una gran cantidad de tipos de datos pequeños (por ejemplo, un mapa donde todo lo que tiene es un byte para el tipo de terreno) puede haber diferencias de rendimiento considerables debido al almacenamiento en caché. La versión de matriz carga varios elementos por lectura de memoria, la versión de lista carga solo uno. Además, la versión de la matriz contiene varias veces más celdas en la memoria caché que la versión de la lista; si está procesando repetidamente los datos, esto puede hacer una gran diferencia si la versión de la matriz cabe en la memoria caché pero la versión de la lista no.
Para un caso extremo, considere Minecraft. (Sí, no está escrito en C #. Se aplica la misma razón).
fuente
T[,]
) son más lentas que las matrices irregulares equivalentes (por ejemploT[][]
) .Una matriz de 100 elementos de algún tipo T encapsula 100 variables independientes de tipo T. Si T es un tipo de valor que tiene un campo público mutable de tipo Q y uno de tipo R, entonces cada elemento de la matriz encapsulará variables independientes de los tipos Q y R. La matriz en su conjunto encapsulará así 100 variables independientes del tipo Q y 100 variables independientes del tipo R; Se puede acceder a cualquiera de esas variables individualmente sin afectar a ninguna otra. Ningún tipo de colección que no sean matrices puede permitir que los campos de estructuras se utilicen como variables independientes.
Si, en cambio, T es un tipo de clase con campos públicos mutables de tipo Q y R, cada elemento de la matriz tiene la única referencia, en cualquier parte del universo, a una instancia de
T
, y si ninguno de los elementos de la matriz alguna vez se modifique para identificar un objeto para el cual existe alguna referencia externa, entonces la matriz encapsulará efectivamente 100 variables independientes de tipo Q y 100 variables independientes de tipo R. Otros tipos de colección pueden imitar el comportamiento de dicha matriz, pero si el único propósito de la matriz es encapsular 100 variables de tipo Q y 100 de tipo R, encapsular cada par de variables en su propio objeto de clase es una forma costosa de hacerlo. Promover,El uso de una matriz o colección de tipo de clase mutable crea la posibilidad de que las variables identificadas por los elementos de la matriz no sean independientes .Si se supone que un tipo se comporta como algún tipo de objeto, debe ser un tipo de clase o una estructura de campo privado que no proporcione otro medio de mutación que no sea el reemplazo. Sin embargo, si se supone que un tipo se comporta como un conjunto de variables relacionadas pero independientes unidas con cinta adhesiva, entonces se debe usar un tipo que es un conjunto de variables unidas con cinta adhesiva, una estructura de campo expuesto . Las matrices de este tipo son muy eficientes para trabajar y tienen una semántica muy limpia. El uso de cualquier otro tipo conducirá a una semántica confusa, un rendimiento inferior o ambos.
fuente
Una diferencia importante es la asignación de memoria. Por ejemplo, atravesar una lista vinculada podría ocasionar muchos errores de caché y un rendimiento más lento, mientras que una matriz representa una porción contigua de memoria que contiene múltiples instancias de algún tipo de datos en particular, y atravesarla en orden es más probable que golpee la CPU cache.
Por supuesto, una serie de referencias a objetos puede no beneficiarse tanto de los éxitos de caché, ya que la desreferenciación podría llevarlo a cualquier parte de la memoria.
Luego están las implementaciones de listas como ArrayList, que implementan una lista usando una matriz. Son primitivas útiles para tener.
fuente
List<T>
, que no se implementa usando una lista vinculada, sino usando una matriz (es esencialmente equivalente aArrayList<T>
en Java).Aquí hay algunas pautas que puede usar sobre cuándo seleccionar
Array
y cuándo seleccionarList
.Array
cuando regrese de un método.List
como variable cuando construya el valor de retorno (dentro del método). Luego, use.ToArray()
cuando regrese del método.En general, use un
Array
cuando no tenga la intención de que el consumidor agregue elementos a la colección. ÚseloList
cuando desee que el consumidor agregue elementos a la colección.Array
está destinado a tratar con colecciones "estáticas", mientras queList
está destinado a tratar con colecciones "dinámicas".fuente
Array
lugar deList
. ¡Es bueno escuchar tus pensamientos!