MyClass[] array;
List<MyClass> list;
¿Cuáles son los escenarios cuando uno es preferible al otro? ¿Y por qué?
MyClass[] array;
List<MyClass> list;
¿Cuáles son los escenarios cuando uno es preferible al otro? ¿Y por qué?
Respuestas:
Es raro, en realidad, que desee utilizar una matriz. Definitivamente use un en List<T>
cualquier momento que desee agregar / eliminar datos, ya que cambiar el tamaño de las matrices es costoso. Si sabe que los datos tienen una longitud fija y desea realizar una micro optimización por alguna razón muy específica (después de la evaluación comparativa), una matriz puede ser útil.
List<T>
ofrece mucha más funcionalidad que una matriz (aunque LINQ lo iguala un poco), y casi siempre es la elección correcta. Excepto por params
argumentos, por supuesto. ;-pags
Como contador, List<T>
es unidimensional; donde-ya que tiene matrices rectangulares (etc.) como int[,]
o string[,,]
- pero hay otras formas de modelar dichos datos (si es necesario) en un modelo de objetos.
Ver también:
Dicho esto, uso mucho las matrices en mi proyecto protobuf-net ; enteramente para el rendimiento:
byte[]
es bastante esencial para la codificación;byte[]
búfer rodante local que lleno antes de enviarlo a la secuencia subyacente (y vv); más rápido que BufferedStream
etc.Foo[]
lugar de List<Foo>
), ya que el tamaño se fija una vez construido y debe ser muy rápido.Pero esto es definitivamente una excepción; para el procesamiento general de la línea de negocio, un List<T>
gana cada vez.
Realmente solo respondo para agregar un enlace que me sorprende que aún no se haya mencionado: la entrada del blog de Eric Lippert sobre "Matrices consideradas algo dañinas".
Puede juzgar por el título que sugiere usar colecciones siempre que sea práctico, pero como Marc señala con razón, hay muchos lugares donde una matriz realmente es la única solución práctica.
A pesar de las otras respuestas recomendadas List<T>
, querrá usar matrices cuando maneje:
List<T>
conjunto de bytes aquí en lugar de uno?
A menos que esté realmente preocupado por el rendimiento, y con eso quiero decir, "¿Por qué estás usando .Net en lugar de C ++?" deberías seguir con la Lista <>. Es más fácil de mantener y hace todo el trabajo sucio de cambiar el tamaño de una matriz detrás de escena por usted. (Si es necesario, List <> es bastante inteligente sobre la elección de tamaños de matriz, por lo que generalmente no es necesario).
Las matrices deben usarse con preferencia a la Lista cuando la inmutabilidad de la colección en sí misma es parte del contrato entre el código del cliente y el proveedor (no necesariamente la inmutabilidad de los artículos dentro de la colección) Y cuando IEnumerable no es adecuado.
Por ejemplo,
var str = "This is a string";
var strChars = str.ToCharArray(); // returns array
Está claro que la modificación de "strChars" no mutará el objeto "str" original, independientemente del nivel de implementación del tipo subyacente de "str".
Pero supongamos que
var str = "This is a string";
var strChars = str.ToCharList(); // returns List<char>
strChars.Insert(0, 'X');
En este caso, no está claro por ese fragmento de código solo si el método de inserción mutará o no el objeto "str" original. Se requiere conocimiento de nivel de implementación de String para tomar esa determinación, lo que rompe el enfoque de Diseño por Contrato. En el caso de String, no es un gran problema, pero puede ser un gran problema en casi todos los demás casos. Establecer la Lista en solo lectura ayuda pero resulta en errores de tiempo de ejecución, no en tiempo de compilación.
To
va a crear un objeto que no tiene capacidad para modificar la instancia original, a diferencia de lo strChars as char[]
que si es válido, sugeriría que ahora puede modificar el objeto original.
str
utiliza internamente una matriz y ToCharArray
devuelve una referencia a esta matriz, el cliente puede mutar str
cambiando los elementos de esa matriz, incluso si el tamaño permanece fijo. Sin embargo, escribe 'Está claro que la modificación de "strChars" no mutará el objeto "str" original'. ¿Que me estoy perdiendo aqui? Por lo que puedo ver, en cualquier caso, el cliente puede tener acceso a la representación interna y, independientemente del tipo, esto permitiría la mutación de algún tipo.
Si sé exactamente cuántos elementos que voy a necesidad, decir que necesito 5 elementos y sólo alguna vez 5 elementos, entonces yo uso una matriz. De lo contrario, solo uso una Lista <T>.
La mayoría de las veces, usar un List
sería suficiente. A List
usa una matriz interna para manejar sus datos, y automáticamente cambia el tamaño de la matriz al agregar más elementos a List
su capacidad actual, lo que hace que sea más fácil de usar que una matriz, donde necesita conocer la capacidad de antemano.
Consulte http://msdn.microsoft.com/en-us/library/ms379570(v=vs.80).aspx#datastructures20_1_topic5 para obtener más información sobre las listas en C # o simplemente descompilar System.Collections.Generic.List<T>
.
Si necesita datos multidimensionales (por ejemplo, utilizando una matriz o en la programación de gráficos), probablemente iría con un array
en su lugar.
Como siempre, si la memoria o el rendimiento son un problema, ¡mídelo! De lo contrario, podría estar haciendo suposiciones falsas sobre el código.
Arreglos vs. Listas es un problema clásico de mantenimiento versus rendimiento. La regla general que siguen casi todos los desarrolladores es que debes disparar para ambos, pero cuando entren en conflicto, elige la mantenibilidad sobre el rendimiento. La excepción a esa regla es cuando el rendimiento ya ha demostrado ser un problema. Si llevas este principio a Arrays Vs. Listas, entonces lo que obtienes es esto:
Use listas fuertemente tipadas hasta que encuentre problemas de rendimiento. Si se encuentra con un problema de rendimiento, decida si abandonar los arreglos beneficiará más su solución con el rendimiento que lo que será perjudicial para su solución en términos de mantenimiento.
Otra situación aún no mencionada es cuando uno tendrá una gran cantidad de elementos, cada uno de los cuales consiste en un grupo fijo de variables relacionadas pero independientes unidas (por ejemplo, las coordenadas de un punto o los vértices de un triángulo 3d). Una matriz de estructuras de campo expuesto permitirá que sus elementos se modifiquen eficientemente "en su lugar", algo que no es posible con ningún otro tipo de colección. Debido a que una matriz de estructuras mantiene sus elementos consecutivamente en la RAM, los accesos secuenciales a los elementos de la matriz pueden ser muy rápidos. En situaciones donde el código necesitará hacer muchos pases secuenciales a través de una matriz, una matriz de estructuras puede superar a una matriz u otra colección de referencias de objetos de clase por un factor de 2: 1; más lejos,
Aunque las matrices no son redimensionables, no es difícil que el código almacene una referencia de matriz junto con el número de elementos que están en uso, y reemplace la matriz por una más grande según sea necesario. Alternativamente, uno podría escribir fácilmente código para un tipo que se comportó de manera muy similar a un List<T>
pero expuso su almacén de respaldo, lo que le permite a uno decir MyPoints.Add(nextPoint);
o MyPoints.Items[23].X += 5;
. Tenga en cuenta que este último no necesariamente arrojaría una excepción si el código intentara acceder más allá del final de la lista, pero el uso sería conceptualmente bastante similar a List<T>
.
Point[] arr;
, por ejemplo , es posible que el código diga, por ejemplo arr[3].x+=q;
. Usando List<Point> list
, por ejemplo , sería necesario decirPoint temp=list[3]; temp.x+=q; list[3]=temp;
. Sería útil si List<T>
tuviera un método Update<TP>(int index, ActionByRefRef<T,TP> proc, ref TP params)
. y los compiladores podrían convertir list[3].x+=q;
en {list.Update(3, (ref int value, ref int param)=>value+=param, ref q);
, pero no existe tal función.
list[0].X += 3;
agregará 3 a la propiedad X del primer elemento de la lista. Y list
es un List<Point>
y Point
es una clase con propiedades X e Y
Las listas en .NET son envoltorios sobre matrices y usan una matriz internamente. La complejidad temporal de las operaciones en las listas es la misma que con las matrices, sin embargo, hay un poco más de sobrecarga con toda la funcionalidad agregada / facilidad de uso de las listas (como el cambio de tamaño automático y los métodos que vienen con la clase de lista). Más o menos, recomendaría usar listas en todos los casos a menos que haya una razón convincente para no hacerlo, como si necesita escribir código extremadamente optimizado o si está trabajando con otro código que se construye alrededor de matrices.
En lugar de pasar por una comparación de las características de cada tipo de datos, creo que la respuesta más pragmática es "las diferencias probablemente no sean tan importantes para lo que necesita lograr, especialmente dado que ambas implementan IEnumerable
, así que siga las convenciones populares y use un List
hasta que tenga una razón para no hacerlo, momento en el cual probablemente tendrá su razón para usar una matriz sobre un List
".
La mayoría de las veces en código administrado querrá favorecer que las colecciones sean tan fáciles de trabajar como sea posible en lugar de preocuparse por las micro optimizaciones.
Pueden ser impopulares, pero soy fanático de las matrices en proyectos de juegos. - La velocidad de iteración puede ser importante en algunos casos, foreach en una matriz tiene significativamente menos sobrecarga si no está haciendo mucho por elemento. puede que no importe: en la mayoría de los casos, se desperdicia menos memoria adicional (solo es realmente significativo con matrices de estructuras): un poco menos de basura, punteros y persecución de punteros
Dicho esto, en la práctica uso List con mucha más frecuencia que las matrices, pero cada una tiene su lugar.
Sería bueno si List tuviera un tipo incorporado para que pudieran optimizar la envoltura y la sobrecarga de enumeración.
Completar una lista es más fácil que una matriz. Para las matrices, debe conocer la longitud exacta de los datos, pero para las listas, el tamaño de los datos puede ser cualquiera. Y, puede convertir una lista en una matriz.
List<URLDTO> urls = new List<URLDTO>();
urls.Add(new URLDTO() {
key = "wiki",
url = "https://...",
});
urls.Add(new URLDTO()
{
key = "url",
url = "http://...",
});
urls.Add(new URLDTO()
{
key = "dir",
url = "https://...",
});
// convert a list into an array: URLDTO[]
return urls.ToArray();
Como nadie menciona: en C #, una matriz es una lista. MyClass[]
y List<MyClass>
ambos implementan IList<MyClass>
. (por ejemplo, void Foo(IList<int> foo)
se puede llamar como Foo(new[] { 1, 2, 3 })
o Foo(new List<int> { 1, 2, 3 })
)
Por lo tanto, si está escribiendo un método que acepta a List<MyClass>
como argumento, pero usa solo un subconjunto de características, puede declarar comoIList<MyClass>
para conveniencia de las personas que llaman.
Detalles:
List
, solo implementa la IList
interfaz.
Depende completamente de los contextos en los que se necesita la estructura de datos. Por ejemplo, si está creando elementos para ser utilizados por otras funciones o servicios, usar List es la manera perfecta de lograrlo.
Ahora, si tiene una lista de elementos y solo desea mostrarlos, digamos que en una matriz de páginas web se encuentra el contenedor que necesita usar.
IEnumerable<T>
- luego puedo transmitir objetos en lugar de almacenarlos en búfer.
Vale la pena mencionar sobre la capacidad de hacer casting en el lugar.
interface IWork { }
class Foo : IWork { }
void Test( )
{
List<Foo> bb = new List<Foo>( );
// Error: CS0029 Cannot implicitly convert type 'System.Collections.Generic.List<Foo>' to 'System.Collections.Generic.List<IWork>'
List<IWork> cc = bb;
Foo[] bbb = new Foo[4];
// Fine
IWork[] ccc = bbb;
}
Entonces Array ofrece un poco más de flexibilidad cuando se usa en el tipo de retorno o argumento para funciones.
IWork[] GetAllWorks( )
{
List<Foo> fooWorks = new List<Foo>( );
return fooWorks.ToArray( ); // Fine
}
void ExecuteWorks( IWork[] works ) { } // Also accept Foo[]