Paginação uma coleção com LINQ

votos
69

Como você página através de uma coleção em LINQ, uma vez que você tem um startIndexe um count?

Publicado 01/08/2008 em 14:20
fonte usuário
Em outras línguas...                            


4 respostas

votos
61

É muito simples com os Skipe TakeMétodos de extensão.

var query = from i in ideas
            select i;

var paggedCollection = query.Skip(startIndex).Take(count);
Respondeu 01/08/2008 em 14:22
fonte usuário

votos
38

Alguns meses atrás eu escrevi um post sobre Fluent Interfaces e LINQ que usou um método de extensão em IQueryable<T>e outra classe para fornecer o seguinte caminho natural da pagina 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 da galeria de páginas de código MSDN: Dutos, filtros, API Fluent e LINQ to SQL .

Respondeu 07/08/2008 em 09:22
fonte usuário

votos
12

Eu resolvi isso um pouco diferente do que o que os outros têm como eu tive que fazer o meu próprio paginator, com um repetidor. Então, eu primeiro fez uma coleção de números de página para a coleção de itens que eu tenho:

// 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 este 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>). Isto é como você pode fazer isso usando Skipe Takeem conjunto com a seleção do índice do pageRangecriado acima:

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

Claro que você tem que lidar com cada página como uma coleção adicional, mas, por exemplo, se você está nidificação repetidores então este é realmente fácil de manusear.


O one-liner TLDR versão seria esta:

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

Que pode ser usado como este:

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

    for (Item item : page) 
    {
        // handle item in page
    }
}
Respondeu 20/03/2012 em 13:52
fonte usuário

votos
9

Esta questão é um pouco velho, mas eu queria postar meu algoritmo de paginação que mostra o procedimento todo (incluindo a interacção do utilizador).

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ê estiver após desempenho, e no código de produção, estamos todos após o desempenho, você não deve usar paginação do LINQ, como mostrado acima, mas sim o subjacente IEnumeratorimplementar a paginação si mesmo. Por uma questão de fato, é tão simples como o LINQ-algoritmo mostrado acima, mas o mais alto 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()para várias vezes em uma "forma de cascata" é que ele realmente não vai armazenar o "ponteiro" da iteração, onde foi passada ignorada. - Em vez da sequência original será front-carregado com chamadas Skip, o que levará a "consumir" as páginas já "consumiu" uma e outra vez. - Você pode provar que a si mesmo, quando você cria a seqüência ideaspara que ele produz efeitos colaterais. -> Mesmo que você tenha pulado 10-20 e 20-30 e deseja processar 40+, você verá todos os efeitos secundários de 10-30 sendo executado novamente, antes de começar a iteração 40+. A variante usando IEnumerableinterface 's diretamente, em vez disso, lembre-se a posição do final da última página lógica, por isso não pular explícito é necessário e não será repetido efeitos colaterais.

Respondeu 16/07/2011 em 21:07
fonte usuário

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