使用LINQ分页集合

Nick Berardi 76 linq .net-3.5

如果你有a startIndex和a ,你如何翻阅LINQ中的集合count

Nick Berardi.. 62

使用SkipTake扩展方法非常简单.

var query = from i in ideas
            select i;

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

  • 这最初是在StackOverflow测试期的第一天发布的,因此文章ID为66.我正在为杰夫测试系统.此外,它似乎是有用的信息,而不是通常的测试废话有时来自beta测试. (11认同)
  • 我相信做这样的事情是可以的.他可能有一个答案,但也许他想看看其他人能想出什么. (3认同)

Mike Minutil.. 39

几个月前,我写了一篇关于Fluent Interfaces和LINQ的博客文章,它使用了一个扩展方法IQueryable<T>和另一个类来提供以下自然的分层LINQ集合的方法.

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

您可以从MSDN代码库页面获取代码:管道,过滤器,Fluent API和LINQ to SQL.


Spoike.. 12

我解决这个问题的方式与其他人有所不同,因为我必须使用转发器制作自己的分页器.所以我首先为我拥有的项目集合制作了一组页码:

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

使用这个我可以轻松地将项目集合划分为"页面"集合.在这种情况下,页面只是items(IEnumerable<Item>)的集合.这是你如何使用它Skip,Take以及从pageRange上面创建的索引中选择索引:

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

当然,您必须将每个页面作为附加集合处理,但例如,如果您正在嵌套中继器,那么这实际上很容易处理.


一个班轮TLDR版本是这样的:

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

哪个可以用作:

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

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


Nico.. 9

这个问题有些陈旧,但我想发布我的分页算法,显示整个过程(包括用户交互).

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

但是,如果你是在性能之后,在生产代码中,我们都是在性能之后,你不应该使用如上所示的LINQ的分页,而是IEnumerator自己实现分页的底层.事实上,它就像上面显示的LINQ算法一样简单,但性能更高:

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

说明:Skip()以"级联方式"多次使用的缺点是,它不会真正存储迭代的"指针",它最后被跳过. - 相反,原始序列将在前面加载跳过调用,这将导致"消耗"已经"消耗"的页面一遍又一遍.- 当您创建序列时,您可以证明自己ideas产生副作用. - >即使你已经跳过了10-20和20-30并希望处理40+,你会看到10-30的所有副作用再次被执行,然后再开始迭代40+.IEnumerable直接使用's接口的变体将记住最后一个逻辑页面末尾的位置,因此不需要显式跳过,并且不会重复副作用.