¿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.