Jak zdobyć pierwsze N ​​elementów listy w C #?


384

Chciałbym użyć Linq do zapytania o rozkład jazdy autobusów w moim projekcie, aby w każdej chwili uzyskać kolejne 5 godzin przyjazdu autobusu. Jak mogę ograniczyć moje zapytanie do pierwszych 5 wyników?

Mówiąc bardziej ogólnie, jak mogę pobrać kawałek listy w C #? (W Pythonie chciałbym użyć mylist[:5]pierwszych 5 elementów.)

Odpowiedzi:


706
var firstFiveItems = myList.Take(5);

Lub pokroić:

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

I oczywiście często wygodnie jest zdobyć pierwsze pięć przedmiotów według pewnego rodzaju zamówienia:

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

87
Czy zgłasza wyjątek, jeśli na liście znajdują się tylko 3 elementy? A może zajmie tyle, ile jest do 5?
Bobek

87
@bekek: Nie zgłasza wyjątku. Zwraca po prostu to, co ma, jeśli nie ma wystarczającej liczby elementów.
Joshua Pech,

1
dokładnie, bez wyjątków zgłoszonych Pomiń i weź razem rozwiązało mój problem, ponieważ chciałem wziąć jakąkolwiek ogólną kolekcję i przetwarzać x przedmiotów na partię
JohanLarsson

Należy zauważyć, że .Take(n)zwraca TakeIterator; nie zwraca listy zawierającej nelementy (przy założeniu, że tylu jest dostępnych). Użyj .ToArray()lub .ToList()na wyniku, Takeaby uzyskać konkretną tablicę lub listę.
Andrew Webb

69

W przypadku, gdy ktoś jest zainteresowany (nawet jeśli pytanie nie wymaga tej wersji), w C # 2 byłoby: (Zredagowałem odpowiedź, podążając za niektórymi sugestiami)

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

Może dodać także anonimowy predykat?
AlexeyMK,

2
Lista <T> .Sort zwraca void; musisz posortować, a następnie użyć GetRange osobno. Możesz także użyć anonimowej metody porównania <T>, aby usunąć potrzebę użycia CLASS_FOR_COMPARER.
Marc Gravell

@AlexeyMK - masz na myśli Porównanie <T>, a nie predykat (Predicate <T>) - predykat służy do filtrowania danych
Marc Gravell

Wierzę, że ta odpowiedź jest przydatna nawet teraz, 10 lat i wiele wersji C # później. W konkretnym przypadku, w którym masz listę. Zwłaszcza jeśli pomijasz wiele przedmiotów. Np. Masz listę miliona przedmiotów i chcesz kawałek 5 z nich, daleko na liście. GetRange dokładnie wie, gdzie je zabrać. Nie wiem, czy Skip+ Takejest tak mądry, czy też wylicza pomijane elementy. I nie muszę wiedzieć - po prostu korzystam z GetRange (kiedy dostaje się Listę). Upewnij się tylko, że zdajesz sobie sprawę, że drugim parametrem jest liczba (a nie ostatni indeks ).
ToolmakerSteve

Zaletą .Take(n)jest to, że nie musisz się martwić, jeśli nw sekwencji, w której działa, jest mniej niż elementów. Problem List<T>.GetRange(0, count)polega na tym, że musisz się martwić ... dostaniesz, ArgumentExceptionjeśli nie ma countprzedmiotów.
Andrew Webb

5

Jak paginationmożesz użyć poniższego wzoru do robienia slice of list or elements:

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

Przykład 1: pierwsze pięć pozycji

var pageNumber = 1;
var pageSize = 5;

Przykład 2: drugie pięć pozycji

var pageNumber = 2;
var pageSize = 5;

Przykład 3: trzecie pięć pozycji

var pageNumber = 3;
var pageSize = 5;

Jeśli powiadomienie o formułowaniu parametrów pageSize = 5i pageNumbersię zmienia, jeśli chcesz zmienić liczbę elementów w krojeniu, zmienisz pageSize.


1

Aby wziąć pierwsze 5 elementów, lepiej użyj wyrażenia takiego jak ten:

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

lub

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

Będzie to szybsze niż wariant zamówienia, ponieważ silnik LINQ nie skanuje całej listy z powodu opóźnionego wykonania i nie sortuje całej tablicy.

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
Tyle że teraz zamawiasz tylko pierwsze 5 elementów po ich wybraniu. Może być szybszy, ale ma też inną semantykę, co do której ludzie nie chcą tak naprawdę osiągnąć.
Greg Beech
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.