Søke en samling med LINQ

stemmer
72

Hvordan du kan bla gjennom en samling i LINQ gitt at du har en startIndexog en count?

Publisert på 01/08/2008 klokken 13:20
kilden bruker
På andre språk...                            


4 svar

stemmer
62

Det er meget enkel med Skipog Takeforlengelsesmetoder.

var query = from i in ideas
            select i;

var paggedCollection = query.Skip(startIndex).Take(count);
Svarte 01/08/2008 kl. 13:22
kilden bruker

stemmer
38

For noen måneder tilbake skrev jeg et blogginnlegg om Flytende grensesnitt og LINQ som brukte en utvidelse metode på IQueryable<T>og en annen klasse for å gi følgende naturlige måten paginating et LINQ samling.

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

Du kan få koden fra MSDN Code Gallery Side: Rørledninger, Filtre, Flytende API og LINQ til SQL .

Svarte 07/08/2008 kl. 08:22
kilden bruker

stemmer
12

Jeg løste dette litt annerledes enn hva de andre har, så jeg måtte lage min egen paginator, med en repeater. Så jeg først har gjort en samling av sidetall for innsamling av elementer som jeg har:

// 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]

Ved hjelp av dette kan jeg lett partisjonere elementet samlingen til en samling av "sider". En side i dette tilfellet er bare en samling av elementer ( IEnumerable<Item>). Dette er hvordan du kan gjøre det ved hjelp av Skipog Takesammen med å velge indeksen fra pageRangeopprettet ovenfor:

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

Selvfølgelig må du håndtere hver side som en ekstra samling, men for eksempel hvis du hekkende repeatere så dette er faktisk lett å håndtere.


Den ett-liner TLDR versjon ville være denne:

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

Som kan brukes som dette:

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

    for (Item item : page) 
    {
        // handle item in page
    }
}
Svarte 20/03/2012 kl. 12:52
kilden bruker

stemmer
9

Dette spørsmålet er litt gammel, men jeg ønsket å legge min personsøker algoritme som viser hele prosedyren (inkludert brukermedvirkning).

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

Men hvis du er ute etter ytelse, og i produksjonskode, er vi alle etter ytelse, bør du ikke bruke LINQ er øker som vist ovenfor, men heller den underliggende IEnumeratorfor å gjennomføre bla deg selv. Som et Faktisk er det så enkelt som det LINQ-algoritmen er vist ovenfor, men mer 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);
}

Forklaring: Ulempen med å bruke Skip()for flere ganger i en "gjennomgripende måte" er, at det ikke vil virkelig lagre "pekeren" av iterasjon, hvor det ble siste hoppet. - I stedet den opprinnelige sekvensen vil være front-lastet med krok samtaler, noe som vil føre til "forbruker" allerede "forbrukes" sider om og om igjen. - Du kan bevise at selv, når du oppretter sekvensen ideasslik at den gir bivirkninger. -> Selv om du har hoppet 10-20 og 20-30, og ønsker å behandle 40+, vil du se alle bivirkninger av 10-30 blir utført igjen, før du begynner itera 40+. Varianten bruke IEnumerable's grensesnitt direkte, vil i stedet huske posisjonen til slutten av siste logiske siden, så ingen eksplisitt hoppe er nødvendig og bivirkninger vil ikke bli gjentatt.

Svarte 16/07/2011 kl. 20:07
kilden bruker

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