Stronicowanie kolekcji z LINQ

głosy
69

W jaki sposób strony poprzez gromadzenie w LINQ zważywszy, że masz startIndexa count?

Utwórz 01/08/2008 o 14:20
źródło użytkownik
W innych językach...                            


4 odpowiedzi

głosy
61

Jest to bardzo proste ze Skipi Takerozszerzenie metod.

var query = from i in ideas
            select i;

var paggedCollection = query.Skip(startIndex).Take(count);
Odpowiedział 01/08/2008 o 14:22
źródło użytkownik

głosy
38

Kilka miesięcy temu napisałem blogu o Fluent interfejsów i LINQ, który wykorzystał metodę rozszerzenia na IQueryable<T>i innej klasy, aby podać następujące naturalny sposób Stronicowanie zbiór LINQ.

var query = from i in ideas
            select i;
var pagedCollection = query.InPagesOf(10);
var pageOfIdeas = pagedCollection.Page(2);

Można otrzymać kod z kodu MSDN Gallery Strona: Rurociągi, Filtry, Fluent API i LINQ to SQL .

Odpowiedział 07/08/2008 o 09:22
źródło użytkownik

głosy
9

To pytanie jest nieco stary, ale chciałem pisać mój algorytm stronicowania, który pokazuje całą procedurę (w tym interakcji użytkownika).

const int pageSize = 10;
const int count = 100;
const int startIndex = 20;

int took = 0;
bool getNextPage;
var page = ideas.Skip(startIndex);

do
{
    Console.WriteLine("Page {0}:", (took / pageSize) + 1);
    foreach (var idea in page.Take(pageSize))
    {
        Console.WriteLine(idea);
    }

    took += pageSize;
    if (took < count)
    {
        Console.WriteLine("Next page (y/n)?");
        char answer = Console.ReadLine().FirstOrDefault();
        getNextPage = default(char) != answer && 'y' == char.ToLowerInvariant(answer);

        if (getNextPage)
        {
            page = page.Skip(pageSize);
        }
    }
}
while (getNextPage && took < count);

Jednakże, jeśli jesteś po wydajności, a w kodzie produkcyjnym, wszyscy jesteśmy po wykonaniu, nie należy używać stronicowania LINQ, jak przedstawiono powyżej, lecz instrumentem bazowym IEnumeratordo wdrożenia stronicowania siebie. W rzeczywistości jest to tak proste jak w Linq algorytmu przedstawionego powyżej, ale bardziej wydajnych:

const int pageSize = 10;
const int count = 100;
const int startIndex = 20;

int took = 0;
bool getNextPage = true;
using (var page = ideas.Skip(startIndex).GetEnumerator())
{
    do 
    {
        Console.WriteLine("Page {0}:", (took / pageSize) + 1);

        int currentPageItemNo = 0;
        while (currentPageItemNo++ < pageSize && page.MoveNext())
        {
            var idea = page.Current;
            Console.WriteLine(idea);
        }

        took += pageSize;
        if (took < count)
        {
            Console.WriteLine("Next page (y/n)?");
            char answer = Console.ReadLine().FirstOrDefault();
            getNextPage = default(char) != answer && 'y' == char.ToLowerInvariant(answer);
        }
    }
    while (getNextPage && took < count);
}

Objaśnienie: Minusem korzystania z Skip()wielu czasów w „kaskadowym” jest sposób, że nie będzie naprawdę przechowywać „wskaźnik” z iteracji, gdzie był ostatnio pomijany. - Zamiast oryginalnej sekwencji będzie ładowany od przodu z połączeń kontenerowego, które doprowadzą do „konsumentami” już „zużyte” stron w kółko. - Można udowodnić, że sam podczas tworzenia sekwencji ideastak, że daje skutków ubocznych. -> Nawet jeśli pominąć 10-20 i 20-30 i chcą przetwarzać 40+, zobaczysz wszystkie efekty uboczne 10-30 wykonywane są raz, przed rozpoczęciem iteracji 40+. Wariant używając IEnumerablebezpośrednio interfejsu „s, będzie zamiast zapamiętać położenie końca ostatniej strony logicznej, więc nie ma wyraźnej pomijanie jest potrzebne i skutki uboczne nie będą powtarzane.

Odpowiedział 16/07/2011 o 21:07
źródło użytkownik

głosy
12

Rozwiązałem to trochę inaczej niż to, co inni mają tak musiałem zrobić własny paginator, z repeatera. Więc raz pierwszy zbiór numerów stron do gromadzenia przedmiotów, które mam:

// assumes that the item collection is "myItems"

int pageCount = (myItems.Count + PageSize - 1) / PageSize;

IEnumerable<int> pageRange = Enumerable.Range(1, pageCount);
   // pageRange contains [1, 2, ... , pageCount]

Korzystanie z tego mogę łatwo podzielić kolekcję element do kolekcji „stron”. Strona jest w tym przypadku tylko zbiór przedmiotów ( IEnumerable<Item>). W ten sposób można zrobić to za pomocą Skipi Takerazem z wybierając indeks z pageRangeutworzone powyżej:

IEnumerable<IEnumerable<Item>> pageRange
    .Select((page, index) => 
        myItems
            .Skip(index*PageSize)
            .Take(PageSize));

Oczywiście trzeba obsłużyć każdą stronę jako dodatkowy kolekcji ale np jeśli gniazdowania wzmacniaczy to jest rzeczywiście łatwy w obsłudze.


Jedno-liner TLDR wersja byłoby to:

var pages = Enumerable
    .Range(0, pageCount)
    .Select((index) => myItems.Skip(index*PageSize).Take(PageSize));

Które mogą być wykorzystane jako to:

for (Enumerable<Item> page : pages) 
{
    // handle page

    for (Item item : page) 
    {
        // handle item in page
    }
}
Odpowiedział 20/03/2012 o 13:52
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more