2008-11-26 40 views
276

Me gustaría utilizar Linq para consultar un horario de autobuses en mi proyecto, para que en cualquier momento pueda obtener los próximos 5 horarios de llegada del autobús. ¿Cómo puedo limitar mi consulta a los primeros 5 resultados?¿Cómo obtener los primeros N elementos de una lista en C#?

Más en general, ¿cómo puedo tomar una porción de una lista en C#? (En Python me gustaría utilizar mylist[:5] para obtener los primeros 5 elementos.)

Respuesta

504
var firstFiveItems = myList.Take(5); 

O para rebanar:

var secondFiveItems = myList.Skip(5).Take(5); 

Y, por supuesto, a menudo es conveniente para obtener los primeros cinco elementos de acuerdo a algún tipo de orden:

var firstFiveArrivals = myList.OrderBy(i => i.ArrivalTime).Take(5); 
+55

¿Se lanza una excepción si solo hay, por ejemplo, 3 elementos en la lista? ¿O tomará tantos como hasta 5? –

+53

@bobek: No arroja una excepción. Simplemente devuelve lo que tiene si no hay suficientes elementos. –

+0

exactamente, sin excepciones arrojadas Saltar y tomar combinados resolvió mi problema ya que quería tomar cualquier colección genérica y procesar x elementos por lote – JohanLarsson

57

en caso de que a alguien le interesa (incluso si la pregunta no pide esta versión), en C# 2 sería: (he editado la respuesta, siguiendo algunas sugerencias)

myList.Sort(CLASS_FOR_COMPARER); 
List<string> fiveElements = myList.GetRange(0, 5); 
+0

¿Tal vez agregar también un predicado anónimo? – AlexeyMK

+1

List .Sort devuelve void; deberías ordenar, luego usar GetRange por separado. También puede utilizar el método anónimo Comparación para eliminar la necesidad de CLASS_FOR_COMPARER. –

+0

@AlexeyMK - quiere decir una Comparación , no un predicado (Predicado ) - se usa un predicado para filtrar los datos –

0

Tomar 5 primeros elementos de un mejor uso de expresión como la siguiente:

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5);

o

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5).OrderBy([ORDER EXPR]);

Será más rápido que la variante orderBy, porque el motor LINQ no escanear toda la lista debido a la ejecución retrasada, y no ordenará todas las matrices.

class MyList : IEnumerable<int> 
{ 

    int maxCount = 0; 

    public int RequestCount 
    { 
     get; 
     private set; 
    } 
    public MyList(int maxCount) 
    { 
     this.maxCount = maxCount; 
    } 
    public void Reset() 
    { 
     RequestCount = 0; 
    } 
    #region IEnumerable<int> Members 

    public IEnumerator<int> GetEnumerator() 
    { 
     int i = 0; 
     while (i < maxCount) 
     { 
      RequestCount++; 
      yield return i++; 
     } 
    } 

    #endregion 

    #region IEnumerable Members 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     throw new NotImplementedException(); 
    } 

    #endregion 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     var list = new MyList(15); 
     list.Take(5).ToArray(); 
     Console.WriteLine(list.RequestCount); // 5; 

     list.Reset(); 
     list.OrderBy(q => q).Take(5).ToArray(); 
     Console.WriteLine(list.RequestCount); // 15; 

     list.Reset(); 
     list.Where(q => (q & 1) == 0).Take(5).ToArray(); 
     Console.WriteLine(list.RequestCount); // 9; (first 5 odd) 

     list.Reset(); 
     list.Where(q => (q & 1) == 0).Take(5).OrderBy(q => q).ToArray(); 
     Console.WriteLine(list.RequestCount); // 9; (first 5 odd) 
    } 
} 
+22

Excepto que ahora está ordenando solo los primeros 5 elementos después de haberlos seleccionado. Puede ser más rápido, pero también tiene una semántica diferente, que es menos probable que sea lo que las personas realmente quieren lograr. –

+3

+1 al comentario de Greg: tomar y luego ordenar es casi siempre el enfoque equivocado, IMO. –

+0

Creo que depende de lo que desee para el resultado, no es una simple pregunta en blanco y negro. –

Cuestiones relacionadas