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.