当skip不能被take整除时,通过pageIndex/pageSize分页实现skip/take分页

本文关键字:take 分页 skip pageIndex pageSize 实现 通过 不能 | 更新日期: 2023-09-27 18:07:46

假设我有一些神奇的分页黑盒类,它通过使用pageIndexpageSize检索数据,如下所示:

public class PaginatedList<T>
{
    // ...
    // Chops up the internally stored list into pages of size "pageSize",
    // then returns the page stored at index "pageIndex".
    public IEnumerable<T> Get(int pageIndex, int pageSize)
    {
        // Magic black box code goes here.
    }
    // ...
}

现在假设我有一个想要使用这个PaginatedList类的驱动程序类,但希望通过使用skiptake参数来实现分页。当然,如果我想要的skip的偏移量恰好可以被我想要的take的偏移量整除,那么我可以通过下面的操作来实现这一点:

public class MyDriver
{
    // Bypass the first "skip" elements and return the next "take" elements.
    static IEnumerable<T> OffsetGet(PaginatedList<T> myList, int skip, int take)
    {
        // ASSERT: skip % take == 0 is true.
        return myList.Get(skip/take, take);
    }
    static void Main(string[] args)
    {
        // ...
        // From some dataSource, store some strings in a fancy PaginatedList.
        var myList = new PaginatedList<string>(dataSource);
        // Skip the first 20 strings and take the next 5 strings.
        var myData = OffsetGet(myList, 20, 5);
        // ...
    }
}

但是,对于我想要skip的偏移量可除以我想要take的量的情况,我如何才能有效地实现OffsetGet(myList, skip, take)(即不进行多个Get(pageIndex, pageSize)调用)?

如果这个问题已经在某处得到了回答,或者如果上面的代码太模糊,请道歉;这是我在StackOverflow上的第一个问题,所以请温柔一点。div =]

注意:这个答案有重大问题(被接受,所以不能删除)-例如,跳过28,取5。很遗憾,我没有时间来解决这个问题。


这部分取决于你想在代码复杂性和数据获取效率之间取得多大的平衡。

你可以总是成功获取两倍于你需要的数据:

int virtualTake = take * 2;
int virtualSkip = skip / virtualTake;
var bigList = Get(myList, virtualSkip, virtualTake);
int offset = virtualSkip % take;
var pruned = bigList.Skip(offset).Take(take);
然而,在很多情况下,这会获取比你需要的更多的数据。您可以至少针对skip已经是take的倍数的情况进行优化,但还有其他情况可以改进。

例如,如果您想跳过23并服用5,则上面的将有效地跳过20并服用10,然后修剪…但是你可以跳过21,选择7。基于以下注释中astander建议的代码:

int newTake = take;
while ((skip % newTake) + take > newTake)
{
     newTake++;
}
var bigList = Get(myList, skip / newTake, newTake);
int offset = skip % newTake;
var pruned = bigList.Skip(offset).Take(take);

当skip不能被take整除时,通过pageIndex/pageSize分页实现skip/take分页

您可以直接使用LINQ的Skip和Take方法

return mylist.Skip(skip).Take(take).AsEnumerable();