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

A menudo me encuentro con el caso en el que quiero evaluar una consulta justo donde la declaro. Esto es generalmente porque necesito iterar sobre él varias veces y es costoso de 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 bien Pero si no voy a modificar el resultado, entonces también podría llamar a ToArray() lugar de ToList() .

Sin embargo, me pregunto si ToArray () se implementa llamando primero a ToList () y, por lo tanto, es menos eficiente en memoria que simplemente llamar a ToList ().

¿Estoy loco? ¿Debo simplemente llamar a ToArray() – de forma segura, sabiendo que la memoria no se asignará dos veces?

A menos que simplemente necesite una matriz para cumplir con otras restricciones, debe usar ToList . En la mayoría de los escenarios, ToArray asignará más memoria que ToList .

Ambos usan arrays para almacenamiento, pero ToList tiene una restricción más flexible. Necesita que la matriz sea al menos tan grande como la cantidad de elementos en la colección. Si la matriz es más grande, eso no es un problema. Sin embargo, ToArray necesita que la matriz se ToArray exactamente según la cantidad de elementos.

Para cumplir con esta restricción, ToArray menudo hace una asignación más que ToList . Una vez que tiene una matriz lo suficientemente grande, asigna una matriz que es exactamente del tamaño correcto y copia los elementos nuevamente en esa matriz. El único momento en que puede evitar esto es cuando el algoritmo de crecimiento de la matriz simplemente coincide con la cantidad de elementos que se deben almacenar (definitivamente en minoría).

EDITAR

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

Esta es una preocupación valida. Si la colección creada es de larga duración, nunca se modifica después de ser creada y tiene una alta probabilidad de aterrizar en el montón de Gen2, entonces será mejor que ToArray asignación adicional de ToArray por adelantado.

En general, creo que este es el caso más raro. Es mucho más común ver muchas llamadas a ToArray que pasan inmediatamente a otros usos ToList de la memoria, en cuyo caso ToList es ToList mejor.

La clave aquí es perfil, perfil y luego perfil un poco más.

La diferencia de rendimiento será insignificante, ya que List se implementa como una matriz de tamaño dynamic. Llamar a ToArray() (que usa una clase interna de Buffer para hacer crecer la matriz) o ToList() (que llama al constructor List(IEnumerable) terminará siendo una cuestión de ponerlos en una matriz y creciendo la matriz hasta que se ajuste a todos.

Si desea una confirmación concreta de este hecho, revise la implementación de los métodos en cuestión en Reflector: verá que se reducen a un código casi idéntico.

(siete años despues…)

Un par de otras (buenas) respuestas se han concentrado en las diferencias microscópicas de rendimiento que se producirán.

Esta publicación es solo un complemento para mencionar la diferencia semántica que existe entre el IEnumerator producido por un conjunto ( T[] ) en comparación con el que devuelve List .

Mejor ilustrado con por ejemplo:

 IList source = Enumerable.Range(1, 10).ToArray(); // try changing to .ToList() foreach (var x in source) { if (x == 5) source[8] *= 100; Console.WriteLine(x); } 

El código anterior se ejecutará sin excepción y produce el resultado:

  1
 2
 3
 4
 5
 6
 7
 8
 900
 10 

Esto muestra que IEnumarator devuelto por una int[] no realiza un seguimiento de si la matriz se ha modificado desde la creación del enumerador.

Tenga en cuenta que he declarado el source variable local como IList . De esa manera, me aseguro de que el comstackdor C # no optimice la statement foreach en algo que sea equivalente a un bucle for (var idx = 0; idx < source.Length; idx++) { /* ... */ } . Esto es algo que el comstackdor de C # podría hacer si utilizo var source = ...; en lugar. En mi versión actual del framework .NET, el enumerador real utilizado aquí es un sistema de referencia no público System.SZArrayHelper+SZGenericArrayEnumerator`1[System.Int32] pero, por supuesto, se trata de un detalle de implementación.

Ahora, si cambio .ToArray() en .ToList() , obtengo solo:

  1
 2
 3
 4
 5 

seguido por un blow-up System.InvalidOperationException dice:

La colección fue modificada; la operación de enumeración no se puede ejecutar.

El enumerador subyacente en este caso es el tipo de valor mutable público System.Collections.Generic.List`1+Enumerator[System.Int32] ( IEnumerator dentro de un IEnumerator en este caso porque utilizo IList ).

En conclusión, el enumerador producido por una List realiza un seguimiento de si la lista cambia durante la enumeración, mientras que el enumerador producido por T[] no lo hace. Así que considere esta diferencia al elegir entre .ToList() y .ToArray() .

A menudo, las personas agregan un .ToArray() o .ToList() para eludir una colección que realiza un seguimiento de si se modificó durante la vida de un enumerador.

(Si alguien quiere saber cómo la List<> realiza un seguimiento de si la colección fue modificada, hay una _version campo _version en esta clase que se cambia cada vez que se actualiza la List<> ).

Estoy de acuerdo con @mquander en que la diferencia de rendimiento debería ser insignificante. Sin embargo, quería compararlo para estar seguro, así que lo hice, y es insignificante.

 Testing with List 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 / lista fuente tenía 1000 elementos. Entonces puede ver que las diferencias de tiempo y memoria son insignificantes.

Mi conclusión: también podrías usar ToList () , ya que una List proporciona más funcionalidad que una matriz, a menos que unos pocos bytes de memoria realmente te importen.

La memoria siempre se asignará dos veces, o algo así. Como no puede cambiar el tamaño de una matriz, ambos métodos utilizarán algún tipo de mecanismo para reunir los datos en una colección en crecimiento. (Bueno, la Lista es una colección creciente en sí misma).

La Lista utiliza una matriz como almacenamiento interno y duplica la capacidad cuando sea necesario. Esto significa que, en promedio, 2/3 de los ítems han sido reasignados al menos una vez, la mitad de los reasignados al menos dos veces, la mitad de ellos al menos tres veces, y así sucesivamente. Eso significa que cada artículo ha sido reasignado en promedio 1.3 veces, lo que no es mucho sobrecarga.

Recuerde también que si está creando cadenas, la colección en sí misma solo contiene las referencias a las cadenas, las cadenas en sí mismas no se reasignan.

ToList() generalmente se prefiere si lo usa en IEnumerable (de ORM, por ejemplo). Si la longitud de la secuencia no se conoce al principio, ToArray() crea una colección de longitud dinámica como Lista y luego la convierte en matriz, lo que lleva más tiempo.

Editar : La última parte de esta respuesta no es válida. Sin embargo, el rest sigue siendo información útil, así que lo dejo.

Sé que esta es una publicación anterior, pero después de tener la misma pregunta y hacer algunas investigaciones, he encontrado algo interesante que podría valer la pena compartir.

Primero, estoy de acuerdo con @mquander y su respuesta. Tiene razón al decir que en cuanto a rendimiento, los dos son idénticos.

Sin embargo, he estado usando Reflector para echar un vistazo a los métodos en el espacio de nombres System.Linq.Enumerable extensions, y he notado una optimización muy común.
Siempre que sea posible, la IEnumerable en IList o ICollection para optimizar el método. Por ejemplo, mira ElementAt(int) .

Curiosamente, Microsoft optó por optimizar solo para IList , pero no para IList . Parece que Microsoft prefiere usar la interfaz IList .

System.Array solo implementa IList , por lo que no se beneficiará de ninguna de estas optimizaciones de extensión.
Por lo tanto, presento que la mejor práctica es usar el método .ToList() .
Si utiliza alguno de los métodos de extensión o pasa la lista a otro método, existe la posibilidad de que pueda optimizarse para un IList .

Debes basar tu decisión en ir a ToList o ToArray función de lo que idealmente sea la elección de diseño. Si desea una colección que solo puede ser iterada y accedida por índice, seleccione ToArray . Si desea capacidades adicionales de agregar y eliminar de la colección más adelante sin mucha molestia, realice una lista ToList (no es realmente lo que no puede agregar a una matriz, pero esa no es la herramienta adecuada para ello).

Si el rendimiento importa, también debe considerar lo que sería más rápido para operar. De manera realista, no llamará a ToList o ToArray un millón de veces, pero podría trabajar en la colección obtenida un millón de veces. En ese sentido, [] es mejor, ya que List<> es [] con algunos gastos generales. Vea este hilo para una comparación de eficiencia: Cuál es más eficiente: Lista o int []

En mis propias pruebas hace un tiempo, había encontrado ToArray más rápido. Y no estoy seguro de qué tan sesgadas fueron las pruebas. Sin embargo, la diferencia de rendimiento es tan insignificante, que solo se nota si está ejecutando estas consultas en un bucle millones de veces.

Una respuesta muy tardía, pero creo que será útil para los googlers.

Ambos chupan cuando crearon usando linq. Ambos implementan el mismo código para cambiar el tamaño del búfer si es necesario . ToArray usa internamente una clase para convertir IEnumerable<> en una matriz, asignando una matriz de 4 elementos. Si eso no es suficiente, duplica el tamaño creando una nueva matriz del doble del tamaño actual y copiando la matriz actual. Al final, asigna una nueva matriz de recuento de sus artículos. Si su consulta devuelve 129 elementos, ToArray realizará 6 asignaciones y operaciones de copia de memoria para crear una matriz de 256 elementos y otra matriz de 129 para devolver. tanto para la eficiencia de la memoria.

ToList hace lo mismo, pero omite la última asignación ya que puede agregar elementos en el futuro. A la lista no le importa si se crea a partir de una consulta linq o si se crea manualmente.

para la creación La lista es mejor con la memoria pero peor con la CPU, ya que la lista es una solución genérica. Cada acción requiere verificaciones de rango adicionales a las comprobaciones de rango interno de .Net para las matrices.

Por lo tanto, si repite demasiadas veces el conjunto de resultados, las matrices son buenas, ya que significan menos comprobaciones de rango que las listas, y los comstackdores generalmente optimizan las matrices para el acceso secuencial.

La asignación de inicialización de la lista puede ser mejor si especifica un parámetro de capacidad cuando la crea. En este caso, asignará la matriz solo una vez, suponiendo que conozca el tamaño del resultado. ToList of linq no especifica una sobrecarga para proporcionarlo, entonces tenemos que crear nuestro método de extensión que crea una lista con la capacidad dada y luego usa List<>.AddRange .

Para terminar esta respuesta, tengo que escribir las siguientes oraciones

  1. Al final, puede utilizar ToArray o ToList, el rendimiento no será tan diferente (ver respuesta de @EMP).
  2. Estás usando C #. Si necesita rendimiento, no se preocupe por escribir sobre código de alto rendimiento, pero preocúpese de no escribir código de rendimiento incorrecto.
  3. Siempre apunte x64 para código de alto rendimiento. AFAIK, x64 JIT se basa en el comstackdor de C ++ y realiza algunas cosas divertidas, como optimizaciones de recursividad de cola.
  4. Con 4.5 también puede disfrutar de la optimización guiada de perfil y multi-core JIT.
  5. Por último, puedes usar el patrón async / await para procesarlo más rápido.

Esta es una vieja pregunta, pero para el beneficio de los usuarios que se topan con ella, también existe una alternativa de “Memoizing” the Enumerable, que tiene el efecto de almacenar en caché y detener la enumeración múltiple de una instrucción Linq, que es lo que ToArray () y ToList () se usan mucho, aunque los atributos de colección de la lista o matriz nunca se usan.

Memoize está disponible en el RX / System.Interactive lib, y se explica aquí: Más LINQ con System.Interactive

(Del blog de Bart De’Smet, que es una lectura muy recomendada si trabajas mucho con Linq to Objects)

Encontré que faltaban los otros puntos de referencia que la gente ha hecho aquí, así que aquí está mi oportunidad. Avíseme si encuentra algo mal con mi metodología.

 /* This is a benchmarking template I use in LINQPad when I want to do a * quick performance test. Just give it a couple of actions to test and * it will give you a pretty good idea of how long they take compared * to one another. It's not perfect: You can expect a 3% error margin * under ideal circumstances. But if you're not going to improve * performance by more than 3%, you probably don't care anyway.*/ void Main() { // Enter setup code here var values = Enumerable.Range(1, 100000) .Select(i => i.ToString()) .ToArray() .Select(i => i); values.GetType().Dump(); var actions = new[] { new TimedAction("ToList", () => { values.ToList(); }), new TimedAction("ToArray", () => { values.ToArray(); }), new TimedAction("Control", () => { foreach (var element in values) { // do nothing } }), // Add tests as desired }; const int TimesToRun = 1000; // Tweak this as necessary TimeActions(TimesToRun, actions); } #region timer helper methods // Define other methods and classes here public void TimeActions(int iterations, params TimedAction[] actions) { Stopwatch s = new Stopwatch(); int length = actions.Length; var results = new ActionResult[actions.Length]; // Perform the actions in their initial order. for (int i = 0; i < length; i++) { var action = actions[i]; var result = results[i] = new ActionResult { Message = action.Message }; // Do a dry run to get things ramped up/cached result.DryRun1 = s.Time(action.Action, 10); result.FullRun1 = s.Time(action.Action, iterations); } // Perform the actions in reverse order. for (int i = length - 1; i >= 0; i--) { var action = actions[i]; var result = results[i]; // Do a dry run to get things ramped up/cached result.DryRun2 = s.Time(action.Action, 10); result.FullRun2 = s.Time(action.Action, iterations); } results.Dump(); } public class ActionResult { public string Message { get; set; } public double DryRun1 { get; set; } public double DryRun2 { get; set; } public double FullRun1 { get; set; } public double FullRun2 { get; set; } } public class TimedAction { public TimedAction(string message, Action action) { Message = message; Action = action; } public string Message { get; private set; } public Action Action { get; private set; } } public static class StopwatchExtensions { public static double Time(this Stopwatch sw, Action action, int iterations) { sw.Restart(); for (int i = 0; i < iterations; i++) { action(); } sw.Stop(); return sw.Elapsed.TotalMilliseconds; } } #endregion 

Puede descargar la secuencia de comandos LINQPad aquí .

Resultados: Rendimiento de ToArray vs ToList

Al ajustar el código anterior, descubrirá que:

  1. La diferencia es menos significativa cuando se trata de matrices más pequeñas . Más iteraciones, pero arreglos más pequeños
  2. La diferencia es menos significativa cuando se trata de int s en lugar de string s.
  3. Usar struct grandes en vez de string lleva mucho más tiempo en general, pero realmente no cambia mucho la relación.

Esto concuerda con las conclusiones de las respuestas mejor votadas:

  1. Es poco probable que note una diferencia en el rendimiento a menos que su código produzca con frecuencia muchas listas de datos de gran tamaño. (Hubo solo una diferencia de 200 ms al crear 1000 listas de cadenas de 100K cada una).
  2. ToList() ejecuta constantemente más rápido, y sería una mejor opción si no planea aferrarse a los resultados durante mucho tiempo.

Actualizar

@JonHanna señaló que, dependiendo de la implementación de Select , es posible que una ToList() o ToArray() prediga el tamaño de la colección resultante antes de tiempo. Sustituir. .Select(i => i) en el código anterior con Where(i => true) arroja resultados muy similares en este momento, y es más probable que lo haga independientemente de la implementación de .NET.

Punto de referencia utilizando Where en lugar de Select

Una opción es agregar su propio método de extensión que devuelva un solo ICollection . Esto puede ser mejor que usar ToList o ToArray cuando no desea usar las propiedades de indexación de una matriz / lista, o agregar / eliminar de una lista.

 public static class EnumerableExtension { ///  /// Causes immediate evaluation of the linq but only if required. /// As it returns a readonly ICollection, is better than using ToList or ToArray /// when you do not want to use the indexing properties of an IList, or add to the collection. ///  ///  ///  /// Readonly collection public static ICollection Evaluate(this IEnumerable enumerable) { //if it's already a readonly collection, use it var collection = enumerable as ICollection; if ((collection != null) && collection.IsReadOnly) { return collection; } //or make a new collection return enumerable.ToList().AsReadOnly(); } } 

Pruebas unitarias:

 [TestClass] public sealed class EvaluateLinqTests { [TestMethod] public void EvalTest() { var list = new List {1, 2, 3}; var linqResult = list.Select(i => i); var linqResultEvaluated = list.Select(i => i).Evaluate(); list.Clear(); Assert.AreEqual(0, linqResult.Count()); //even though we have cleared the underlying list, the evaluated list does not change Assert.AreEqual(3, linqResultEvaluated.Count()); } [TestMethod] public void DoesNotSaveCreatingListWhenHasListTest() { var list = new List {1, 2, 3}; var linqResultEvaluated = list.Evaluate(); //list is not readonly, so we expect a new list Assert.AreNotSame(list, linqResultEvaluated); } [TestMethod] public void SavesCreatingListWhenHasReadonlyListTest() { var list = new List {1, 2, 3}.AsReadOnly(); var linqResultEvaluated = list.Evaluate(); //list is readonly, so we don't expect a new list Assert.AreSame(list, linqResultEvaluated); } [TestMethod] public void SavesCreatingListWhenHasArrayTest() { var list = new[] {1, 2, 3}; var linqResultEvaluated = list.Evaluate(); //arrays are readonly (wrt ICollection interface), so we don't expect a new object Assert.AreSame(list, linqResultEvaluated); } [TestMethod] [ExpectedException(typeof (NotSupportedException))] public void CantAddToResultTest() { var list = new List {1, 2, 3}; var linqResultEvaluated = list.Evaluate(); Assert.AreNotSame(list, linqResultEvaluated); linqResultEvaluated.Add(4); } [TestMethod] [ExpectedException(typeof (NotSupportedException))] public void CantRemoveFromResultTest() { var list = new List {1, 2, 3}; var linqResultEvaluated = list.Evaluate(); Assert.AreNotSame(list, linqResultEvaluated); linqResultEvaluated.Remove(1); } } 

Old question but new questioners at all time.

According to source of System.Linq.Enumerable , ToList just return a new List(source) , while ToArray use a new Buffer(source).ToArray() to return a T[] .

About memory allocation:

While running on an IEnumerable only object, ToArray do allocate memory one more time than ToList . But you do not have to care about it in most cases, because GC will do the garbage collection when needed.

About the runtime efficient:

Those who are questioning this question can run the following code on your own machine, and you’ll get your answer.

 class PersonC { public Guid uuid; public string name; public int age; public bool sex; public DateTime BirthDay; public double weight; } struct PersonS { public Guid uuid; public string name; public int age; public bool sex; public DateTime BirthDay; public double weight; } class PersonT : IEnumerable { private List items; public PersonT(IEnumerable init) { items = new List(init); } public IEnumerator GetEnumerator() => items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => items.GetEnumerator(); } private IEnumerable C(int count) { for (var i = 0; i < count; ++i) { var guid = Guid.NewGuid(); var guidBytes = guid.ToByteArray(); //16 bytes yield return new PersonC { uuid = guid, name = guid.ToString(), age = guidBytes[0] ^ guidBytes[7], sex = guidBytes[14] % 2 == 0, BirthDay = DateTime.Now.AddDays(-guidBytes[11] * 18), weight = guidBytes[12] * 100 }; } } private IEnumerable S(int count) { for (var i = 0; i < count; ++i) { var guid = Guid.NewGuid(); var guidBytes = guid.ToByteArray(); //16 bytes yield return new PersonS { uuid = guid, name = guid.ToString(), age = guidBytes[0] ^ guidBytes[7], sex = guidBytes[14] % 2 == 0, BirthDay = DateTime.Now.AddDays(-guidBytes[11] * 18), weight = guidBytes[12] * 100 }; } } private void MakeLog(string test, List log) => Console.WriteLine("{0} {1} ms -> [{2}]", test, log.Average(), string.Join(", ", log) ); private void Test1(int times, int count) { var test = Enumerable.Range(1, times).ToArray(); MakeLog("C.ToList", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = C(count).ToList(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("C.ToArray", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = C(count).ToArray(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("S.ToList", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = S(count).ToList(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("S.ToArray", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = S(count).ToArray(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); } private void Test2(int times, int count) { var test = Enumerable.Range(1, times).ToArray(); var dataC1 = new PersonT(C(count)); var dataS1 = new PersonT(S(count)); MakeLog("C1.ToList", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataC1.ToList(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("C1.ToArray", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataC1.ToArray(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("S1.ToList", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataS1.ToList(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("S1.ToArray", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataS1.ToArray(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); } private void Test3(int times, int count) { var test = Enumerable.Range(1, times).ToArray(); var dataC2 = (ICollection) new List(C(count)); var dataS2 = (ICollection) new List(S(count)); MakeLog("C2.ToList", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataC2.ToList(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("C2.ToArray", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataC2.ToArray(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("S2.ToList", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataS2.ToList(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("S2.ToArray", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataS2.ToArray(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); } private void TestMain() { const int times = 100; const int count = 1_000_000 + 1; Test1(times, count); Test2(times, count); Test3(times, count); } 

I got these results on my machine:

Group1:

 C.ToList 761.79 ms -> [775, 755, 759, 759, 756, 759, 765, 750, 757, 762, 759, 754, 757, 753, 763, 753, 759, 756, 768, 754, 763, 757, 757, 777, 780, 758, 754, 758, 762, 754, 758, 757, 763, 758, 760, 754, 761, 755, 764, 847, 952, 755, 747, 763, 760, 758, 754, 763, 761, 758, 750, 764, 757, 763, 762, 756, 753, 759, 759, 757, 758, 779, 765, 760, 760, 756, 760, 756, 755, 764, 759, 753, 757, 760, 752, 764, 758, 760, 758, 760, 755, 761, 751, 753, 761, 762, 761, 758, 759, 752, 765, 756, 760, 755, 757, 753, 760, 751, 755, 779] C.ToArray 782.56 ms -> [783, 774, 771, 771, 773, 774, 775, 775, 772, 770, 771, 774, 771, 1023, 975, 772, 767, 776, 771, 779, 772, 779, 775, 771, 775, 773, 775, 771, 765, 774, 770, 781, 772, 771, 781, 762, 817, 770, 775, 779, 769, 774, 763, 775, 777, 769, 777, 772, 775, 778, 775, 771, 770, 774, 772, 769, 772, 769, 774, 775, 768, 775, 769, 774, 771, 776, 774, 773, 778, 769, 778, 767, 770, 787, 783, 779, 771, 768, 805, 780, 779, 767, 773, 771, 773, 785, 1044, 853, 775, 774, 775, 771, 770, 769, 770, 776, 770, 780, 821, 770] S.ToList 704.2 ms -> [687, 702, 709, 691, 694, 710, 696, 698, 700, 694, 701, 719, 706, 694, 702, 699, 699, 703, 704, 701, 703, 705, 697, 707, 691, 697, 707, 692, 721, 698, 695, 700, 704, 700, 701, 710, 700, 705, 697, 711, 694, 700, 695, 698, 701, 692, 696, 702, 690, 699, 708, 700, 703, 714, 701, 697, 700, 699, 694, 701, 697, 696, 699, 694, 709, 1068, 690, 706, 699, 699, 695, 708, 695, 704, 704, 700, 695, 704, 695, 696, 702, 700, 710, 708, 693, 697, 702, 694, 700, 706, 699, 695, 706, 714, 704, 700, 695, 697, 707, 704] S.ToArray 742.5 ms -> [742, 743, 733, 745, 741, 724, 738, 745, 728, 732, 740, 727, 739, 740, 726, 744, 758, 732, 744, 745, 730, 739, 738, 723, 745, 757, 729, 741, 736, 724, 744, 756, 739, 766, 737, 725, 741, 742, 736, 748, 742, 721, 746, 1043, 806, 747, 731, 727, 742, 742, 726, 738, 746, 727, 739, 743, 730, 744, 753, 741, 739, 746, 728, 740, 744, 734, 734, 738, 731, 747, 736, 731, 765, 735, 726, 740, 743, 730, 746, 742, 725, 731, 757, 734, 738, 741, 732, 747, 744, 721, 742, 741, 727, 745, 740, 730, 747, 760, 737, 740] C1.ToList 32.34 ms -> [35, 31, 31, 31, 32, 31, 31, 31, 31, 31, 31, 31, 31, 31, 33, 32, 31, 31, 31, 31, 30, 32, 31, 31, 31, 31, 32, 30, 31, 31, 31, 30, 32, 31, 31, 31, 36, 31, 31, 31, 32, 30, 31, 32, 31, 31, 31, 31, 31, 32, 31, 31, 31, 31, 33, 32, 31, 32, 31, 31, 33, 31, 31, 31, 31, 31, 32, 31, 32, 31, 34, 38, 68, 42, 79, 33, 31, 31, 31, 31, 31, 30, 30, 30, 30, 31, 31, 31, 31, 32, 31, 32, 31, 31, 31, 32, 33, 33, 31, 31] C1.ToArray 56.32 ms -> [57, 56, 59, 54, 54, 55, 56, 57, 54, 54, 55, 55, 57, 56, 59, 57, 56, 58, 56, 56, 54, 56, 57, 55, 55, 55, 57, 58, 57, 58, 55, 55, 56, 55, 57, 56, 56, 59, 56, 56, 56, 56, 58, 56, 57, 56, 56, 57, 56, 55, 56, 56, 56, 59, 56, 56, 56, 55, 55, 54, 55, 54, 57, 56, 56, 56, 55, 55, 56, 56, 56, 59, 56, 56, 57, 56, 57, 56, 56, 56, 56, 62, 55, 56, 56, 56, 69, 57, 58, 56, 57, 58, 56, 57, 56, 56, 56, 56, 56, 56] S1.ToList 88.69 ms -> [96, 90, 90, 89, 91, 88, 89, 90, 96, 89, 89, 89, 90, 90, 90, 89, 90, 90, 89, 90, 89, 91, 89, 91, 89, 91, 89, 90, 90, 89, 87, 88, 87, 88, 87, 87, 87, 87, 88, 88, 87, 87, 89, 87, 87, 87, 91, 88, 87, 86, 89, 87, 90, 89, 89, 90, 89, 87, 87, 87, 86, 87, 88, 90, 88, 87, 87, 92, 87, 87, 88, 88, 88, 86, 86, 87, 88, 87, 87, 87, 89, 87, 89, 87, 90, 89, 89, 89, 91, 89, 90, 89, 90, 88, 90, 90, 90, 88, 89, 89] S1.ToArray 143.26 ms -> [130, 129, 130, 131, 133, 130, 131, 130, 135, 137, 130, 136, 132, 131, 130, 131, 132, 130, 132, 136, 130, 131, 157, 153, 194, 364, 176, 189, 203, 194, 189, 192, 183, 140, 142, 147, 145, 134, 159, 158, 142, 167, 130, 143, 145, 144, 160, 154, 156, 153, 153, 164, 142, 145, 137, 134, 145, 143, 142, 135, 133, 133, 135, 134, 134, 139, 139, 133, 134, 141, 133, 132, 133, 132, 133, 131, 135, 132, 133, 132, 128, 128, 130, 132, 129, 129, 129, 129, 129, 128, 134, 129, 129, 129, 129, 128, 128, 137, 130, 131] C2.ToList 3.25 ms -> [5, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 3, 3, 4, 4, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 4, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3] C2.ToArray 3.37 ms -> [4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 4, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 4, 4, 3, 3, 4, 4, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 4, 4, 3, 4, 4, 3, 3, 4, 3, 3, 4, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 4, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3] S2.ToList 37.72 ms -> [38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 40, 38, 38, 39, 39, 38, 38, 38, 38, 37, 37, 37, 37, 39, 37, 37, 39, 38, 37, 37, 37, 37, 39, 38, 37, 37, 38, 37, 38, 37, 37, 38, 37, 37, 37, 38, 37, 37, 36, 37, 38, 37, 39, 37, 39, 38, 37, 38, 38, 38, 38, 38, 38, 37, 38, 38, 38, 38, 38, 37, 38, 37, 37, 38, 37, 37, 39, 41, 37, 38, 38, 37, 37, 37, 37, 38, 37, 37, 37, 40, 37, 37, 37, 37, 39, 38] S2.ToArray 38.86 ms -> [39, 37, 39, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 38, 38, 38, 39, 37, 38, 38, 38, 38, 38, 37, 37, 38, 37, 37, 38, 38, 40, 38, 38, 38, 38, 38, 39, 38, 38, 39, 38, 38, 39, 38, 38, 40, 38, 39, 38, 38, 39, 38, 38, 38, 38, 38, 39, 38, 38, 38, 39, 39, 37, 38, 38, 39, 71, 78, 37, 37, 37, 39, 38, 38, 39, 38, 38, 38, 38, 38, 39, 38, 38, 38, 39, 38, 38, 38] 

Group2:

 C.ToList 756.81 ms C.ToArray 774.21 ms S.ToList 709.7 ms S.ToArray 753.51 ms C1.ToList 32.06 ms C1.ToArray 56.58 ms S1.ToList 89.43 ms S1.ToArray 132.85 ms C2.ToList 3.45 ms C2.ToArray 3.36 ms S2.ToList 41.43 ms S2.ToArray 40.84 ms 

Group3:

 C.ToList 756.64 ms C.ToArray 771.56 ms S.ToList 705.42 ms S.ToArray 749.59 ms C1.ToList 31.45 ms C1.ToArray 57.03 ms S1.ToList 91.26 ms S1.ToArray 129.77 ms C2.ToList 3.26 ms C2.ToArray 3.29 ms S2.ToList 41.57 ms S2.ToArray 40.69 ms 

Group4:

 C.ToList 729.65 ms -> [749, 730, 721, 719, 723, 743, 721, 724, 727, 722, 716, 725, 723, 726, 718, 722, 731, 722, 723, 725, 723, 722, 728, 726, 728, 718, 726, 1088, 788, 737, 729, 710, 730, 728, 717, 723, 728, 721, 722, 728, 722, 736, 723, 729, 732, 724, 726, 727, 728, 728, 726, 726, 725, 727, 725, 728, 728, 718, 724, 725, 726, 724, 726, 729, 727, 722, 722, 725, 725, 728, 724, 727, 738, 717, 726, 723, 725, 725, 727, 724, 720, 726, 726, 723, 727, 730, 723, 721, 725, 727, 727, 733, 720, 722, 722, 725, 722, 725, 728, 726] C.ToArray 788.36 ms -> [748, 740, 742, 797, 1090, 774, 781, 787, 784, 786, 786, 782, 781, 781, 784, 783, 783, 781, 783, 787, 783, 784, 775, 789, 784, 785, 778, 774, 781, 783, 786, 781, 780, 788, 778, 785, 777, 781, 786, 782, 781, 787, 782, 787, 784, 773, 783, 782, 781, 777, 783, 781, 785, 788, 777, 776, 784, 784, 783, 789, 778, 781, 791, 768, 779, 783, 781, 787, 786, 781, 784, 781, 785, 781, 780, 809, 1155, 780, 790, 789, 783, 776, 785, 783, 786, 787, 782, 782, 787, 777, 779, 784, 783, 776, 786, 775, 782, 779, 784, 784] S.ToList 705.54 ms -> [690, 705, 709, 708, 702, 707, 703, 696, 703, 702, 700, 703, 700, 707, 705, 699, 697, 703, 695, 698, 707, 697, 711, 710, 699, 700, 708, 707, 693, 710, 704, 691, 702, 700, 703, 700, 705, 700, 703, 695, 709, 705, 698, 699, 709, 700, 699, 704, 691, 705, 703, 700, 708, 1048, 710, 706, 706, 692, 702, 705, 695, 701, 710, 697, 698, 706, 705, 707, 707, 695, 698, 704, 698, 699, 705, 698, 703, 702, 701, 697, 702, 702, 704, 703, 699, 707, 703, 705, 701, 717, 698, 695, 713, 696, 708, 705, 697, 699, 700, 698] S.ToArray 745.01 ms -> [751, 743, 727, 734, 736, 745, 739, 750, 739, 750, 758, 739, 744, 738, 730, 744, 745, 739, 744, 750, 733, 735, 743, 731, 749, 748, 727, 746, 749, 731, 737, 803, 1059, 756, 769, 748, 740, 745, 741, 746, 749, 732, 741, 742, 732, 744, 746, 737, 742, 739, 733, 744, 741, 729, 746, 760, 725, 741, 764, 739, 750, 751, 727, 745, 738, 727, 735, 741, 720, 736, 740, 733, 741, 746, 731, 749, 756, 740, 738, 736, 732, 741, 741, 733, 741, 744, 736, 742, 742, 735, 743, 746, 729, 748, 765, 743, 734, 742, 728, 749] C1.ToList 32.27 ms -> [36, 31, 31, 32, 31, 32, 31, 30, 32, 30, 30, 30, 34, 32, 31, 31, 31, 31, 31, 31, 31, 32, 38, 51, 68, 57, 35, 30, 31, 31, 30, 30, 33, 30, 31, 34, 31, 34, 32, 31, 31, 31, 31, 32, 30, 30, 31, 30, 31, 31, 32, 31, 31, 31, 32, 31, 31, 31, 32, 31, 33, 31, 31, 32, 30, 30, 30, 30, 30, 33, 30, 33, 32, 31, 30, 31, 31, 32, 32, 31, 35, 31, 34, 31, 31, 32, 31, 31, 32, 31, 32, 31, 31, 35, 31, 31, 31, 31, 31, 32] C1.ToArray 56.72 ms -> [58, 56, 57, 57, 59, 58, 58, 57, 56, 59, 57, 55, 55, 54, 56, 55, 56, 56, 57, 59, 56, 55, 58, 56, 55, 55, 55, 55, 58, 58, 55, 57, 57, 56, 57, 57, 57, 57, 59, 59, 56, 57, 56, 57, 57, 56, 57, 59, 58, 56, 57, 57, 57, 58, 56, 56, 59, 56, 59, 57, 57, 57, 57, 59, 57, 56, 57, 56, 58, 56, 57, 56, 57, 59, 55, 58, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 56, 56, 57, 56, 56, 57, 58, 57, 57, 57, 57, 57] S1.ToList 90.72 ms -> [95, 90, 90, 89, 89, 89, 91, 89, 89, 87, 91, 89, 89, 89, 91, 89, 89, 89, 90, 89, 89, 90, 88, 89, 88, 90, 89, 90, 89, 89, 90, 90, 89, 89, 90, 91, 89, 91, 89, 90, 89, 89, 90, 91, 89, 89, 89, 89, 89, 89, 90, 89, 89, 89, 90, 89, 90, 89, 91, 89, 90, 89, 90, 89, 90, 89, 96, 89, 90, 89, 89, 89, 89, 89, 90, 89, 89, 89, 90, 87, 89, 90, 90, 91, 89, 91, 89, 89, 90, 91, 90, 89, 93, 144, 149, 90, 90, 89, 89, 89] S1.ToArray 131.4 ms -> [130, 128, 127, 134, 129, 129, 130, 136, 131, 130, 132, 132, 133, 131, 132, 131, 133, 132, 130, 131, 132, 131, 130, 133, 133, 130, 130, 131, 131, 131, 132, 134, 131, 131, 132, 131, 132, 131, 134, 131, 131, 130, 131, 131, 130, 132, 129, 131, 131, 131, 132, 131, 133, 134, 131, 131, 132, 132, 131, 133, 131, 131, 130, 133, 131, 130, 134, 132, 131, 132, 132, 131, 131, 134, 131, 131, 132, 132, 131, 130, 138, 130, 130, 131, 132, 132, 130, 134, 131, 131, 132, 131, 130, 132, 133, 131, 131, 131, 130, 131] C2.ToList 3.21 ms -> [4, 3, 3, 3, 4, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 3, 3, 4, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 4, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 4, 3, 3, 3] C2.ToArray 3.22 ms -> [4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 4, 3, 4, 3, 3, 3, 3, 3, 4, 3, 3, 3, 4, 3, 4, 3, 3, 3, 3, 4] S2.ToList 41.46 ms -> [42, 40, 41, 40, 42, 40, 40, 40, 40, 40, 40, 40, 40, 41, 40, 40, 41, 40, 40, 40, 39, 41, 41, 39, 40, 40, 43, 40, 39, 40, 40, 40, 40, 40, 40, 41, 40, 40, 40, 43, 40, 43, 75, 76, 47, 39, 40, 40, 40, 40, 42, 40, 41, 40, 40, 40, 44, 41, 40, 42, 42, 40, 41, 41, 41, 41, 41, 40, 41, 41, 41, 41, 42, 41, 40, 41, 41, 42, 42, 41, 40, 41, 41, 41, 41, 41, 40, 42, 40, 42, 41, 41, 41, 43, 41, 41, 41, 41, 42, 41] S2.ToArray 41.14 ms -> [42, 41, 41, 40, 40, 40, 40, 41, 41, 42, 41, 42, 41, 41, 41, 42, 41, 41, 42, 41, 41, 41, 41, 41, 42, 40, 41, 40, 42, 40, 42, 41, 40, 42, 41, 41, 43, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 40, 40, 41, 41, 41, 40, 42, 41, 41, 41, 41, 41, 40, 41, 41, 42, 41, 41, 41, 42, 41, 41, 41, 41, 41, 41, 42, 42, 42, 41, 45, 46, 41, 40, 41, 41, 42, 41, 41, 41, 41, 41, 41, 40, 41, 43, 40, 40, 40, 40, 43, 41] 

Group5:

 C.ToList 757.06 ms -> [770, 752, 752, 751, 778, 763, 761, 763, 747, 758, 748, 747, 754, 749, 752, 753, 756, 762, 750, 753, 756, 749, 755, 757, 755, 756, 755, 744, 753, 758, 747, 751, 759, 751, 761, 755, 746, 752, 752, 749, 746, 752, 753, 755, 752, 755, 754, 754, 966, 937, 749, 759, 748, 747, 754, 749, 755, 750, 746, 754, 757, 752, 753, 745, 758, 755, 761, 753, 751, 755, 755, 752, 746, 756, 755, 746, 742, 751, 751, 749, 752, 751, 756, 756, 755, 742, 749, 754, 749, 756, 753, 751, 754, 752, 751, 754, 753, 749, 755, 756] C.ToArray 772.8 ms -> [766, 772, 755, 763, 758, 767, 763, 762, 761, 768, 769, 763, 770, 757, 765, 760, 766, 759, 764, 761, 760, 777, 1102, 881, 759, 765, 758, 762, 772, 761, 758, 757, 765, 769, 769, 761, 762, 762, 763, 760, 770, 764, 760, 768, 758, 766, 763, 770, 769, 761, 764, 761, 761, 767, 761, 762, 764, 757, 765, 766, 767, 771, 753, 762, 769, 768, 759, 764, 764, 760, 763, 763, 763, 763, 763, 767, 761, 771, 760, 765, 760, 758, 768, 770, 751, 771, 767, 771, 765, 763, 760, 765, 765, 769, 767, 767, 1193, 774, 767, 764] S.ToList 704.73 ms -> [682, 708, 705, 699, 705, 704, 695, 703, 702, 699, 701, 708, 699, 702, 703, 701, 701, 699, 701, 707, 707, 700, 701, 705, 700, 697, 706, 702, 701, 706, 699, 692, 702, 697, 707, 704, 697, 698, 699, 699, 702, 703, 698, 697, 702, 703, 702, 704, 694, 697, 707, 695, 711, 710, 700, 693, 703, 699, 699, 706, 698, 701, 703, 704, 698, 706, 700, 704, 701, 699, 702, 705, 694, 698, 709, 736, 1053, 704, 694, 700, 698, 696, 701, 700, 700, 706, 706, 692, 698, 707, 703, 695, 703, 699, 694, 708, 695, 694, 706, 695] S.ToArray 744.17 ms -> [746, 740, 725, 740, 739, 731, 746, 760, 735, 738, 740, 734, 744, 748, 737, 744, 745, 727, 736, 738, 728, 743, 745, 735, 748, 760, 739, 748, 762, 742, 741, 747, 733, 746, 758, 742, 742, 741, 724, 744, 747, 727, 740, 740, 729, 742, 757, 741, 740, 742, 726, 739, 746, 1133, 749, 737, 730, 740, 747, 733, 747, 752, 731, 747, 742, 730, 741, 749, 731, 749, 743, 730, 747, 742, 731, 737, 745, 734, 739, 735, 727, 743, 752, 731, 744, 742, 729, 740, 746, 731, 739, 746, 733, 745, 743, 733, 739, 742, 727, 737] C1.ToList 31.71 ms -> [35, 32, 32, 30, 31, 33, 31, 32, 32, 31, 31, 32, 32, 33, 32, 31, 31, 32, 31, 32, 32, 32, 31, 32, 33, 32, 31, 31, 31, 32, 31, 34, 31, 31, 32, 33, 32, 32, 31, 32, 34, 32, 31, 32, 33, 31, 32, 32, 31, 32, 32, 32, 32, 32, 32, 31, 31, 32, 31, 33, 30, 31, 32, 30, 30, 33, 32, 32, 34, 31, 31, 31, 31, 32, 31, 31, 31, 31, 32, 31, 31, 33, 31, 32, 32, 32, 33, 32, 31, 31, 31, 31, 31, 32, 32, 33, 32, 31, 31, 32] C1.ToArray 59.53 ms -> [63, 57, 58, 58, 57, 59, 59, 57, 60, 131, 127, 67, 58, 56, 59, 56, 57, 58, 58, 58, 57, 59, 60, 57, 57, 59, 60, 57, 57, 57, 58, 58, 58, 58, 57, 57, 61, 57, 58, 57, 57, 57, 57, 57, 58, 58, 58, 58, 57, 58, 59, 57, 58, 57, 57, 59, 58, 58, 59, 57, 59, 57, 56, 56, 59, 56, 56, 59, 57, 58, 58, 58, 57, 58, 59, 59, 58, 57, 58, 62, 65, 57, 57, 57, 58, 60, 59, 58, 59, 57, 58, 57, 58, 59, 58, 58, 58, 59, 60, 58] S1.ToList 82.78 ms -> [87, 82, 83, 83, 82, 82, 83, 84, 82, 83, 84, 84, 84, 82, 82, 84, 82, 84, 83, 84, 82, 82, 82, 81, 83, 83, 83, 84, 84, 82, 82, 83, 83, 83, 82, 83, 85, 83, 82, 82, 84, 82, 82, 83, 83, 83, 82, 82, 82, 83, 82, 83, 82, 84, 82, 83, 82, 83, 82, 82, 82, 84, 82, 83, 82, 82, 86, 83, 83, 82, 83, 83, 83, 82, 84, 82, 83, 81, 82, 82, 82, 82, 83, 83, 83, 82, 83, 84, 83, 82, 83, 83, 83, 82, 83, 84, 82, 82, 83, 83] S1.ToArray 122.3 ms -> [122, 119, 119, 120, 119, 120, 120, 121, 119, 119, 122, 120, 120, 120, 122, 120, 123, 120, 120, 120, 121, 123, 120, 120, 120, 121, 120, 121, 122, 120, 123, 119, 121, 118, 121, 120, 120, 120, 119, 124, 119, 121, 119, 120, 120, 120, 120, 120, 122, 121, 123, 230, 203, 123, 119, 119, 122, 119, 120, 120, 120, 122, 120, 121, 120, 121, 120, 121, 120, 121, 120, 120, 120, 121, 122, 121, 123, 119, 119, 119, 119, 121, 120, 120, 120, 122, 121, 122, 119, 120, 120, 121, 121, 120, 121, 120, 121, 118, 118, 118] C2.ToList 3.43 ms -> [5, 3, 4, 4, 4, 3, 4, 4, 4, 4, 4, 3, 3, 3, 4, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 4, 3, 3, 3, 3, 4, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 6, 4, 4, 3, 3, 4, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 4, 3, 4, 4, 4, 3, 4, 4, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 4, 4, 3, 3, 3, 3] C2.ToArray 3.48 ms -> [3, 3, 3, 3, 4, 4, 3, 4, 4, 4, 3, 4, 3, 3, 4, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 4, 3, 3, 4, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 4, 3, 3, 4, 3, 3, 4, 3, 3, 4, 4, 3, 3, 4, 3, 4, 4, 3, 4, 4, 4, 4, 4, 3, 3, 3, 4, 4, 3, 4, 4, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 3] S2.ToList 41.47 ms -> [41, 41, 49, 67, 82, 41, 41, 40, 40, 40, 40, 40, 41, 40, 40, 40, 40, 40, 41, 40, 42, 42, 40, 40, 41, 41, 41, 40, 41, 40, 41, 40, 41, 40, 42, 41, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 42, 41, 41, 41, 42, 40, 41, 40, 40, 40, 42, 40, 41, 42, 41, 42, 41, 42, 40, 41, 41, 41, 41, 41, 41, 41, 41, 40, 41, 40, 41, 41, 41, 40, 41, 41, 40, 40, 41, 41, 41, 41, 41, 43, 40, 40, 41, 42, 41] S2.ToArray 40.62 ms -> [42, 41, 44, 40, 40, 40, 40, 41, 41, 40, 41, 41, 41, 40, 41, 41, 40, 41, 41, 40, 41, 40, 40, 41, 42, 41, 41, 41, 40, 40, 40, 40, 40, 41, 41, 42, 40, 41, 41, 41, 41, 41, 40, 42, 40, 40, 41, 41, 41, 40, 41, 40, 40, 40, 40, 40, 41, 40, 40, 41, 40, 40, 40, 40, 41, 40, 41, 41, 41, 40, 41, 41, 40, 41, 40, 41, 42, 40, 41, 41, 42, 41, 41, 40, 41, 40, 41, 40, 41, 41, 40, 40, 40, 41, 41, 40, 40, 40, 40, 40] 

Due to stackoverflow’s limit to the characters amount of the answer, the sample lists of Group2 and Group3 are omitted.

As you can see, it’s really not important to use ToList or ToArry in most cases.

While processing runtime-calculated IEnumerable objects, if the load brought by calculation is heavy than memory allocation and copy operations of ToList and ToArray , the disparity is insignificant ( C.ToList vs C.ToArray and S.ToList vs S.ToArray ).

The difference can be observed only on non-runtime-calculated IEnumerable only objects ( C1.ToList vs C1.ToArray and S1.ToList vs S1.ToArray ). But the absolute difference (<60ms) is still acceptable on an one million small object IEnumerable . In fact, the difference is decided by the implementation of Enumerator of IEnumerable . So, if your program is really really really sensitive on this, you do have to profile, profile, profile ! At last you’ll probably find that the bottleneck is not on ToList or ToArray , but the detail of enumerators.

And, the result of C2.ToList vs C2.ToArray and S2.ToList vs S2.ToArray shows that, you really don’t need to care ToList or ToArray on non-runtime-calculated ICollection objects.

Of course, this is just results on my machine, the actual time spend of these operations on different machine will not be the same, you can find out on your machine using code above.

The only reason you need to make a choice is that, you have specific needs on List or T[] , as described by the answer of @Jeppe Stig Nielsen .

For anyone interested in using this result in another Linq-to-sql such as

 from q in context.MyTable where myListOrArray.Contains(q.someID) select q; 

then the SQL that is generated is the same whether you used a List or Array for the myListOrArray. Now I know some may ask why even enumerate before this statement, but there is a difference between the SQL generated from an IQueryable vs (List or Array).

ToListAsync() is preferred.

In Entity Framework 6 both methods eventually call to the same internal method, but ToArrayAsync() calls list.ToArray() at the end, which is implemented as

 T[] array = new T[_size]; Array.Copy(_items, 0, array, 0, _size); return array; 

So ToArrayAsync() has some overheads, thereby ToListAsync() is preferred.