430 votos

¿Es mejor llamar ToList () o ToArray () en las consultas LINQ?

Me funcionan a menudo en el caso de que me quiere eval un derecho de consulta donde me lo declare. Esto es generalmente porque tengo necesidad de iterar varias veces y es muy caro para calcular. Por ejemplo:

string raw = "...";
var lines = (from l in raw.Split('\n')
             let ll = l.Trim()
             where !string.IsNullOrEmpty(ll)
             select ll).ToList();

Esto funciona muy bien. Pero si yo no voy a modificar el resultado, a continuación, que bien podría llamar a ToArray() en lugar de ToList().

Me pregunto sin embargo si el método ToArray() se implementa por primera llamada ToList() y es por lo tanto menos eficiente de la memoria que pedir ToList().

¿Estoy loca? Debo solo llame ToArray() - a salvo y seguro en el conocimiento de que la memoria no será asignado dos veces?

269voto

JaredPar Puntos 333733

A menos que usted simplemente necesita una matriz para satisfacer otras restricciones, usted debe utilizar ToList. En la mayoría de escenarios ToArray va a asignar más memoria de la que ToList.

Tanto el uso de las matrices de almacenamiento, pero ToList dispone de una restricción más flexible. Se necesita de la matriz a ser al menos tan grande como el número de elementos de la colección. Si la matriz es mayor, que no es un problema. Sin embargo, ToArray de las necesidades de la matriz a la que se adapta exactamente al número de elementos.

Para cumplir con esta restricción ToArray a menudo una mayor asignación de ToList. Una vez que se tiene una matriz que es lo suficientemente grande como se asigna una matriz que es exactamente el tamaño correcto y copias de los elementos en la matriz. El único momento en que puede evitar esto es cuando el crecimiento algoritmo para la matriz sólo coincide con el número de elementos que necesitan ser almacenados (definitivamente en la minoría).

EDITAR

Un par de personas me han preguntado acerca de la consecuencia de tener el extra de memoria no utilizada en el List<T> valor.

Esta es una preocupación válida. Si el creado de la colección es de larga duración, no se modifica nunca, después de ser creado y tiene una alta probabilidad de aterrizaje en el Gen2 montón, a continuación, puede ser mejor tomar la extra de asignación de ToArray hasta el frente.

En general, aunque me parece que este es el más raro de los casos. Es mucho más común ver a un montón de ToArray las llamadas que se pasa inmediatamente a otros de corta duración de los usos de la memoria, en cuyo caso ToList es notablemente mejor.

La clave aquí es de perfil, de perfil y, a continuación, el perfil de algunos más.

154voto

mquander Puntos 32650

La diferencia de rendimiento será insignificante, ya List<T> está implementado como un dinámicamente el tamaño de la matriz. Llamando a cualquiera ToArray() (que utiliza una interna Buffer<T> clase a crecer la matriz) o ToList() (que llama a las List<T>(IEnumerable<T>) constructor) va a terminar siendo una cuestión de poner en una matriz y creciente de la matriz hasta que se adapte a todos ellos.

Si deseo concreto de la confirmación de este hecho, retirar la aplicación de los métodos en cuestión en el Reflector, se verá que se reducen a casi idéntico código.

23voto

EMP Puntos 17246

Estoy de acuerdo con @mquander que la diferencia de rendimiento debe ser insignificante. Sin embargo, yo quería punto de referencia para estar seguro, así que lo hice - y no es insignificante.

Testing with List<T> source:
ToArray time: 1934 ms (0.01934 ms/call), memory used: 4021 bytes/array
ToList  time: 1902 ms (0.01902 ms/call), memory used: 4045 bytes/List

Testing with array source:
ToArray time: 1957 ms (0.01957 ms/call), memory used: 4021 bytes/array
ToList  time: 2022 ms (0.02022 ms/call), memory used: 4045 bytes/List

Cada matriz source/List tenía 1000 elementos. Así que usted puede ver que tanto el tiempo y la memoria diferencias son insignificantes.

Mi conclusión: usted podría utilizar ToList(), ya que un List<T> proporciona más funcionalidad que la de una matriz, salvo un par de bytes de memoria que realmente te importan.

19voto

Guffa Puntos 308133

La memoria siempre será asignado dos veces - o algo parecido a eso. Como no se puede cambiar el tamaño de un array, ambos métodos se utilizan algún tipo de mecanismo para recopilar los datos en una colección creciente. (Bueno, la Lista es una colección creciente en sí mismo.)

La Lista se utiliza una matriz de almacenamiento interno, y se duplica la capacidad cuando sea necesario. Esto significa que por medio de 2/3 de los elementos ha sido reasignado al menos una vez, la mitad de los reasignados al menos dos veces, la mitad de los que al menos tres veces, y así sucesivamente. Eso significa que cada elemento tiene por promedio sido reasignado a 1,3 veces, que no está muy por encima.

Recuerde también que si usted es recolectar las cadenas, la colección en sí sólo contiene las referencias a las cadenas, las cadenas no se reasignen.

19voto

Vitaliy Ulantikov Puntos 2834

ToList() es generalmente preferido si usted lo usa en IEnumerable<T> (de ORM, por ejemplo). Si la longitud de la secuencia no se conoce por el principio, ToArray() crea la colección de longitud dinámica como la lista y luego la convierte en matriz, lo que requiere tiempo extra.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X