Vă mulțumim pentru susținere

Trimiteți o colecție cu LINQ

Cum faceți o pagină printr-o colecție în LINQ, având în vedere că aveți un startIndex și un count ?

0
adăugat editat

4 răspunsuri

Este foarte simplu cu metodele de extensie Skip și Take .

var query = from i in ideas
            select i;

var paggedCollection = query.Skip(startIndex).Take(count);
0
adăugat
Acesta a fost inițial postat în prima zi a perioadei beta a StackOverflow, astfel 66 pentru ID-ul articolului. Testem sistemul, pentru Jeff. În plus, aceasta părea o informație utilă în loc de crapul de testare obișnuit, care uneori iese din testarea beta.
adăugat autor Nick Berardi
Cred că e bine să faci așa ceva. Ar putea avea un răspuns, dar poate că vrea să vadă cu ce pot să vină și alte persoane.
adăugat autor Outlaw Programmer

A few months back I wrote a blog post about Fluent Interfaces and LINQ which used an Extension Method on IQueryable and another class to provide the following natural way of paginating a LINQ collection.

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

Puteți obține codul din pagina Galeria de cod MSDN: Conducte, filtre, API fluent și LINQ la SQL .

0
adăugat

Această întrebare este oarecum veche, dar am vrut să post pe algoritmul de paginare care arată întreaga procedură (inclusiv interacțiunea cu utilizatorul).

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);

Cu toate acestea, dacă sunteți după performanță și în codul de producție, suntem cu toții după performanță, nu ar trebui să utilizați paginarea LINQ așa cum este arătată mai sus, ci mai degrabă IEnumerator care stau la baza pentru a implementa personal paginarea. De fapt, este la fel de simplu ca algoritmul LINQ prezentat mai sus, dar mai performant:

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);
}

Explanation: The downside of using Skip() for multiple times in a "cascading manner" is, that it will not really store the "pointer" of the iteration, where it was last skipped. - Instead the original sequence will be front-loaded with skip calls, which will lead to "consuming" the already "consumed" pages over and over again. - You can prove that yourself, when you create the sequence ideas so that it yields side effects. -> Even if you have skipped 10-20 and 20-30 and want to process 40+, you'll see all side effects of 10-30 being executed again, before you start iterating 40+. The variant using IEnumerable's interface directly, will instead remember the position of the end of the last logical page, so no explicit skipping is needed and side effects won't be repeated.

0
adăugat

Am rezolvat acest lucru un pic diferit de ceea ce au ceilalți, așa cum trebuia să-mi fac propriul paginator, cu un repetor. Așadar, am făcut prima dată o colecție de numere de pagini pentru colecția de articole pe care le am:

// assumes that the item collection is "myItems"

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

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

Using this I could easily partition the item collection into a collection of "pages". A page in this case is just a collection of items (IEnumerable). This is how you can do it using Skip and Take together with selecting the index from the pageRange created above:

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

Desigur, trebuie să ocupați fiecare pagină ca o colecție suplimentară, dar de ex. dacă repetiți cuiburi, atunci acest lucru este de fapt ușor de manevrat.


Versiunea one-liner TLDR ar fi aceasta:

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

Care poate fi folosit ca:

for (Enumerable page : pages) 
{
    // handle page

    for (Item item : page) 
    {
        // handle item in page
    }
}
0
adăugat