Pergunta

Como você folheia uma coleção no LINQ, visto que você tem um startIndex e um count?

Foi útil?

Solução

Alguns meses atrás, escrevi uma postagem no blog sobre Fluent Interfaces e LINQ que usava um método de extensão em IQueryable<T> e outra classe para fornecer a seguinte maneira natural de paginar uma coleção LINQ.

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

Você pode obter o código na página da Galeria de Códigos do MSDN: Pipelines, filtros, API fluente e LINQ to SQL.

Outras dicas

É muito simples com o Skip e Take métodos de extensão.

var query = from i in ideas
            select i;

var paggedCollection = query.Skip(startIndex).Take(count);

Resolvi isso de forma um pouco diferente dos outros, pois tive que fazer meu próprio paginador, com repetidor.Então, primeiro fiz uma coleção de números de páginas para a coleção de itens que possuo:

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

Usando isso eu poderia facilmente particionar a coleção de itens em uma coleção de "páginas".Uma página, neste caso, é apenas uma coleção de itens (IEnumerable<Item>).É assim que você pode fazer isso usando Skip e Take juntamente com a seleção do índice do pageRange criado acima:

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

É claro que você precisa lidar com cada página como uma coleção adicional, mas, por exemplo.se você estiver aninhando repetidores, isso será realmente fácil de manusear.


O TLDR de uma linha versão seria esta:

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

Que pode ser usado assim:

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

    for (Item item : page) 
    {
        // handle item in page
    }
}

Esta questão é um pouco antiga, mas eu queria postar meu algoritmo de paginação que mostra todo o procedimento (incluindo a interação do usuário).

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

No entanto, se você busca desempenho, e no código de produção, todos nós buscamos desempenho, você não deve usar a paginação do LINQ como mostrado acima, mas sim o subjacente IEnumerator para implementar a paginação você mesmo.Na verdade, é tão simples quanto o algoritmo LINQ mostrado acima, mas com melhor desempenho:

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

Explicação:A desvantagem de usar Skip() por várias vezes de "maneira em cascata" é que ele realmente não armazenará o "ponteiro" da iteração, onde foi ignorado pela última vez.- Em vez disso, a sequência original será carregada antecipadamente com chamadas de salto, o que levará ao "consumo" das páginas já "consumidas" repetidas vezes.- Você mesmo pode provar isso ao criar a sequência ideas para que produza efeitos colaterais.-> Mesmo que você tenha pulado 10-20 e 20-30 e queira processar 40+, você verá todos os efeitos colaterais de 10-30 sendo executados novamente, antes de começar a iterar 40+.A variante usando IEnumerablediretamente, lembrará a posição do final da última página lógica, portanto, nenhum salto explícito será necessário e os efeitos colaterais não serão repetidos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top