Con C# 8 obtuvimos rangos para obtener "sublistas".
Mientras esto funciona:
var array = new string[] { "abc", "def", "ghi" }; var subArray = array[0..1]; // worksEsto no lo hace:
var list = new List<string> { "abc", "def", "ghi" }; var subList = list[0..1]; // does not work¿Cómo puedo usar rangos con listas?
Desafortunadamente no puedes. De la especificación del idioma:
Por ejemplo, los siguientes tipos de .NET admiten índices y rangos: String, Span y ReadOnlySpan. La lista admite índices pero no admite rangos.
Entonces, la única forma sería algo como esto, que es un poco torpe:
var subList = list.ToArray()[0..1]; Editar: dejaré el resto de mi respuesta aquí para el registro, pero creo que la respuesta usando Range es más elegante y será significativamente más rápida, especialmente para cortes grandes.
Lo siguiente demuestra cuánto más lento puede ser el uso de ToArray() (usando LINQPad - F.Rnd.Str es mi propio método auxiliar para generar cadenas aleatorias):
var list = new List<string>(); for (int i = 0; i < 100000; i++) { list.Add(F.Rnd.Str); } // Using ToArray() var timer = new Stopwatch(); timer.Start(); var subList0 = list.ToArray()[42..142]; timer.Stop(); timer.ElapsedTicks.Dump("ToArray()"); // Using Indices timer.Reset(); timer.Start(); var subList1 = new List<string>(); for (int i = 42; i < 142; i++) { subList1.Add(list[i]); } timer.Stop(); timer.ElapsedTicks.Dump("Index"); // ToArray() // 3136 // Index // 28Por lo tanto, un método de extensión como este será muy rápido:
public static class ListExtensions { public static List<T> GetSlice<T>(this List<T> @this, int first, int last) { var slice = new List<T>(); for (int i = first; i < last; i++) { slice.Add(@this[i]); } return slice; } }Luego puede agregar esto al punto de referencia:
// Using Extension Method timer.Reset(); timer.Start(); var subList2 = list.GetSlice(42, 142); timer.Stop(); timer.ElapsedTicks.Dump("Extension");Resultados de referencia:
// ToArray() // 2021 // Index // 16 // Extension // 15 Una de las respuestas usa Range para lograr lo mismo, así que para comparar:
timer.Reset(); timer.Start(); var range = new Range(42, 142); var (start, length) = range.GetOffsetAndLength(list.Count); var subList3 = list.GetRange(start, length); timer.Stop(); timer.ElapsedTicks.Dump("Range");Resultados de referencia:
// ToArray() // 2056 // Index // 21 // Extension // 16 // Range // 17Puede ver que los tres métodos inferiores son esencialmente los mismos en términos de velocidad (como lo ejecuto varias veces, todos varían entre 15 y 21 tics).
Puede usar el método ToArray() para resolver el problema:
var list = new List<string> { "abc", "def", "ghi" }; var subList = list.ToArray()[0..1]; // works Pero tenga en cuenta que List<T> tiene el método GetRange que hace lo mismo:
var list = new List<string> { "abc", "def", "ghi" }; var subList = list.GetRange(0,1);//abcSolo para completar, sé que esto no es exactamente lo que pide OP.
List<T> tiene un GetRange -Method.
https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.getrange?view=net-5.0
List<?> range = list.GetRange(0,5);No tiene mucho que ver con la nueva función de idioma, pero hace lo que dice.
Por favor, no use ToArray solo para usar esa función de lenguaje nuevo y elegante. No vale la pena los gastos generales.
La lista en sí misma no admite rangos. Sin embargo, si todo lo que tiene es un rango, puede crear un método de extensión útil como este:
public static class ListExtensions { public static List<T> GetRange<T>(this List<T> list, Range range) { var (start, length) = range.GetOffsetAndLength(list.Count); return list.GetRange(start, length); } }Luego puede usarlo para obtener su sub-Lista:
var list = new List<string> { "abc", "def", "ghi" }; var subList = list.GetRange(0..1);