¿Cómo obtener los primeros N elementos de una lista en C #?


384

Me gustaría usar Linq para consultar un horario de autobuses en mi proyecto, para que en cualquier momento pueda obtener los próximos 5 horarios de llegada de autobuses. ¿Cómo puedo limitar mi consulta a los primeros 5 resultados?

En términos más generales, ¿cómo puedo tomar una porción de una lista en C #? (En Python, usaría mylist[:5]para obtener los primeros 5 elementos).

Respuestas:


709
var firstFiveItems = myList.Take(5);

O para cortar:

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

Y, por supuesto, a menudo es conveniente obtener los primeros cinco artículos de acuerdo con algún tipo de orden:

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

87
¿Lanza una excepción si solo hay, por ejemplo, 3 elementos en la lista? ¿O tomará tantos como haya hasta 5?
bobek

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

1
exactamente, sin excepciones lanzadas Skip and Take combinadas resolvieron mi problema ya que quería tomar cualquier colección genérica y procesar x artículos por lote
JohanLarsson

Cabe señalar que .Take(n)devuelve un TakeIterator; no devuelve una lista con nelementos (suponiendo que hay muchos disponibles). Use .ToArray()o .ToList()en el resultado de Takepara obtener una matriz o lista concreta.
Andrew Webb

69

En caso de que alguien esté interesado (incluso si la pregunta no solicita 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);

¿Quizás agregar un predicado anónimo también?
AlexeyMK

2
List <T> .Sort devuelve void; necesitaría ordenar, luego usar GetRange por separado. También puede utilizar un método anónimo de comparación <T> para eliminar la necesidad de CLASS_FOR_COMPARER.
Marc Gravell

@AlexeyMK: quiere decir una comparación <T>, no un predicado (Predicate <T>): se usa un predicado para filtrar datos
Marc Gravell

Creo que esta respuesta es útil incluso ahora, 10 años y muchas versiones de C # más adelante. Para el caso específico donde tiene una lista. Especialmente si te estás saltando muchos artículos. Por ejemplo, tiene una lista de un millón de elementos, y desea una porción de 5 de ellos, muy lejos en la lista. GetRange sabe exactamente dónde ir para agarrarlos. No sé si Skip+ Takees tan inteligente o si enumera los elementos omitidos. Y no necesito saberlo: solo uso GetRange (cuando se me da una Lista). Solo asegúrese de darse cuenta de que el segundo parámetro es el recuento (en lugar del último índice ).
ToolmakerSteve

Lo bueno .Take(n)es que no tiene que preocuparse si hay menos de nelementos en la secuencia en la que funciona. El problema List<T>.GetRange(0, count)es que tienes que preocuparte ... obtendrás un ArgumentExceptionsi no hay countelementos.
Andrew Webb

5

Como paginationpuede usar a continuación la fórmula para tomar slice of list or elements:

var slice = myList.Skip((pageNumber - 1) * pageSize)
                  .Take(pageSize);

Ejemplo 1: primeros cinco artículos

var pageNumber = 1;
var pageSize = 5;

Ejemplo 2: segundos cinco artículos

var pageNumber = 2;
var pageSize = 5;

Ejemplo 3: terceros cinco elementos

var pageNumber = 3;
var pageSize = 5;

Si observa que los parámetros de la fórmula pageSize = 5y pageNumberestá cambiando, si desea cambiar el número de elementos en el corte, cambia pageSize.


1

Para tomar los primeros 5 elementos, use una expresión como esta:

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á toda la matriz.

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)
    }
}

25
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 la gente realmente quiere lograr.
Greg Beech
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.