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

时间:2014-06-10 05:39:13

标签: c# pagination ienumerable

假设我有一些神奇分页的黑盒子类,它使用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);

        // ...
    }
}

但是,如果我希望OffsetGet(myList, skip, take) by的偏移量Get(pageIndex, pageSize)(也就是说,不会进行多次skip调用) >不可以被我想要take的数量整除?

如果这个问题已在某个地方得到解答或上述代码过于模糊,请道歉;这是我在StackOverflow上的第一个问题,所以请保持温和。 =]

2 个答案:

答案 0 :(得分:4)

这在一定程度上取决于您希望平衡代码复杂性与数据获取效率之间的差异。

您可以通过获取所需数据的两倍来始终成功:

int virtualTake = take * 2;
int virtualSkip = skip / virtualTake;
var bigList = Get(myList, virtualSkip / virtualTake, virtualTake);
int offset = virtualSkip % take;
var pruned = bigList.Skip(offset).Take(take);

但是,在许多情况下,这将获取比您需要的数据更多的数据。对于skip已经是take的倍数的情况,你可以至少进行优化,但在其他情况下你可以改进。

例如,如果你想跳过23并取5,上面将有效地跳过20并取10,然后修剪......但你可以跳过21而取而代之的是7。代码基于旁观者的建议,在下面的评论中:

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

答案 1 :(得分:-1)

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

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