Come ottenere i primi N elementi di un elenco in C #?


384

Vorrei utilizzare Linq per interrogare un programma di autobus nel mio progetto, in modo che in qualsiasi momento sia possibile ottenere i prossimi 5 orari di arrivo dell'autobus. Come posso limitare la mia query ai primi 5 risultati?

Più in generale, come posso prendere una fetta di un elenco in C #? (In Python userei mylist[:5]per ottenere i primi 5 elementi.)

Risposte:


709
var firstFiveItems = myList.Take(5);

O per tagliare:

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

E ovviamente spesso è conveniente ottenere i primi cinque articoli in base a un tipo di ordine:

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

87
Fa eccezione se ci sono solo, ad esempio, 3 elementi nell'elenco? O ne occorrerà quante ne esistono fino a 5?
bobek,

87
@bobek: non genera un'eccezione. Restituisce semplicemente quello che ha se non ci sono abbastanza elementi.
Joshua Pech,

1
esattamente, nessuna eccezione generata Skip and Take combinata ha risolto il mio problema, poiché volevo prendere qualsiasi raccolta generica ed elaborare x articoli per lotto
JohanLarsson,

Va notato che .Take(n)restituisce un TakeIterator; non restituisce un elenco con nelementi al suo interno (supponendo che molti siano disponibili). Utilizzare .ToArray()o .ToList()sul risultato di Takeper ottenere un array o un elenco concreto.
Andrew Webb,

69

Nel caso qualcuno fosse interessato (anche se la domanda non richiede questa versione), in C # 2 sarebbe: (Ho modificato la risposta, seguendo alcuni suggerimenti)

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

Forse aggiungi anche un predicato anonimo?
AlexeyMK,

2
Elenco <T> .Sort restituisce null; dovresti ordinare, quindi utilizzare GetRange separatamente. Puoi anche utilizzare un metodo anonimo di confronto <T> per rimuovere la necessità di CLASS_FOR_COMPARER.
Marc Gravell

@AlexeyMK - intendi un confronto <T>, non un predicato (Predicato <T>) - un filtrato viene utilizzato per filtrare i dati
Marc Gravell

Credo che questa risposta sia utile anche adesso, 10 anni e molte versioni successive di C #. Per il caso specifico in cui hai un elenco. Soprattutto se stai saltando molti oggetti. Ad esempio, hai un elenco di un milione di elementi e ne vuoi una fetta di 5, in fondo all'elenco. GetRange sa esattamente dove andare per afferrarli. Non so se Skip+ Takesia altrettanto intelligente o se sia presente negli elementi ignorati. E non ho bisogno di saperlo, utilizzo semplicemente GetRange (quando mi viene fornito un elenco). Assicurati solo di capire che il secondo parametro è count (anziché l' ultimo indice ).
ToolmakerSteve

La cosa bella .Take(n)è che non devi preoccuparti se ci sono meno di nelementi nella sequenza su cui funziona. Il problema List<T>.GetRange(0, count)è che devi preoccuparti .... otterrai un messaggio ArgumentExceptionse non ci sono countarticoli.
Andrew Webb,

5

Come paginationpuoi usare sotto il formule per prendere slice of list or elements:

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

Esempio 1: primi cinque elementi

var pageNumber = 1;
var pageSize = 5;

Esempio 2: secondi cinque elementi

var pageNumber = 2;
var pageSize = 5;

Esempio 3: terzi cinque elementi

var pageNumber = 3;
var pageSize = 5;

Se si nota di formulare i parametri pageSize = 5e pageNumbersta cambiando, se si desidera modificare il numero di elementi nel taglio si cambia pageSize.


1

Per prendere i primi 5 elementi meglio usare espressioni come questa:

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

o

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

Sarà più veloce della variante orderBy, perché il motore LINQ non eseguirà la scansione di tutto l'elenco a causa dell'esecuzione ritardata e non ordinerà tutto l'array.

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
Solo che ora stai ordinando solo i primi 5 elementi dopo averli selezionati. Potrebbe essere più veloce, ma ha anche una semantica diversa, che ha meno probabilità di essere ciò che le persone vogliono effettivamente ottenere.
Greg Beech,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.