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.