Wie bekomme ich die ersten N Elemente einer Liste in C #?


384

Ich möchte Linq verwenden, um einen Busfahrplan in meinem Projekt abzufragen, damit ich jederzeit die nächsten 5 Busankunftszeiten erhalten kann. Wie kann ich meine Abfrage auf die ersten 5 Ergebnisse beschränken?

Wie kann ich allgemein einen Teil einer Liste in C # erstellen? (In Python würde ich verwenden mylist[:5], um die ersten 5 Elemente zu erhalten.)

Antworten:


706
var firstFiveItems = myList.Take(5);

Oder in Scheiben schneiden:

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

Und natürlich ist es oft bequem, die ersten fünf Artikel in einer bestimmten Reihenfolge zu erhalten:

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

87
Wird eine Ausnahme ausgelöst, wenn beispielsweise nur 3 Elemente in der Liste enthalten sind? Oder dauert es so viele wie es bis zu 5 gibt?
Bobek

87
@ Bobek: Es wird keine Ausnahme ausgelöst. Es gibt einfach zurück, was es hat, wenn nicht genügend Elemente vorhanden sind.
Joshua Pech

1
Genau, keine Ausnahmen geworfen Skip and Take kombiniert löste mein Problem, da ich eine generische Sammlung nehmen und x Artikel pro Charge verarbeiten wollte
JohanLarsson

Es ist zu beachten, dass .Take(n)ein TakeIterator zurückgegeben wird. Es wird keine Liste mit nElementen zurückgegeben (vorausgesetzt, dass viele verfügbar sind). Verwenden Sie .ToArray()oder .ToList()das Ergebnis von Take, um ein konkretes Array oder eine Liste zu erhalten.
Andrew Webb

69

Falls jemand interessiert ist (auch wenn die Frage nicht nach dieser Version fragt), wäre in C # 2: (Ich habe die Antwort nach einigen Vorschlägen bearbeitet)

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

Vielleicht auch ein anonymes Prädikat hinzufügen?
AlexeyMK

2
List <T> .Sort gibt void zurück; Sie müssten sortieren und dann GetRange separat verwenden. Sie können auch eine anonyme Vergleichsmethode <T> verwenden, um die Notwendigkeit von CLASS_FOR_COMPARER zu beseitigen.
Marc Gravell

@AlexeyMK - Sie meinen einen Vergleich <T>, kein Prädikat (Prädikat <T>) - ein Prädikat wird zum Filtern von Daten verwendet
Marc Gravell

Ich glaube, diese Antwort ist auch jetzt noch nützlich, 10 Jahre und viele C # -Versionen später. Für den speziellen Fall, in dem Sie eine Liste haben. Vor allem, wenn Sie viele Elemente überspringen. ZB haben Sie eine Liste mit einer Million Elementen, und Sie möchten ein Stück mit 5 davon weit in der Liste haben. GetRange weiß genau, wohin es gehen muss, um sie zu holen. Ich weiß nicht, ob Skip+ Takeso schlau ist oder ob es die übersprungenen Elemente auflistet. Und ich muss es nicht wissen - ich benutze nur GetRange (wenn ich eine Liste bekomme). Stellen Sie einfach sicher, dass der zweite Parameter count ist (und nicht der letzte Index ).
ToolmakerSteve

Das Schöne daran .Take(n)ist, dass Sie sich keine Sorgen machen müssen, wenn ndie Sequenz, an der es arbeitet, weniger als Elemente enthält. Das Problem dabei List<T>.GetRange(0, count)ist, dass Sie sich Sorgen machen müssen ... Sie erhalten eine, ArgumentExceptionwenn es keine countArtikel gibt.
Andrew Webb

5

Wie paginationSie die folgende Formel für die Einnahme verwenden können slice of list or elements:

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

Beispiel 1: Die ersten fünf Punkte

var pageNumber = 1;
var pageSize = 5;

Beispiel 2: zweite fünf Punkte

var pageNumber = 2;
var pageSize = 5;

Beispiel 3: dritte fünf Punkte

var pageNumber = 3;
var pageSize = 5;

Wenn Sie die Parameter formulieren pageSize = 5und pageNumbersich ändern, ändern Sie die Anzahl der Elemente beim Schneiden pageSize.


1

Um die ersten 5 Elemente besser zu verwenden, verwenden Sie einen Ausdruck wie diesen:

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

oder

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

Es ist schneller als die orderBy-Variante, da die LINQ-Engine aufgrund der verzögerten Ausführung nicht alle Listen durchsucht und nicht alle Arrays sortiert.

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
Außer dass Sie jetzt nur die ersten 5 Elemente bestellen, nachdem Sie sie ausgewählt haben. Es mag schneller sein, aber es hat auch eine andere Semantik, die weniger wahrscheinlich das ist, was die Leute tatsächlich erreichen wollen.
Greg Beech
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.