Paging with Linq to objects

by Alex Siepman 16. May 2014 20:22

Paging with Linq (to objects) seems quite simple:

public static IEnumerable<TSource> GetPage<TSource>(this IEnumerable<TSource> source, 
                                                         int pageNumber, 
                                                         int pageSize)
{
    return source.Skip((pageNumber - 1) * pageSize).Take(pageSize);
}

This is handy when you need a page 'in the middle only' but if you need to enumerate all pages, you have to caculate the number of pages yourself. The next method will help you to get all pages:

public static IEnumerable<IEnumerable<T>> PagesOf<T>(this IEnumerable<T> source, int pageSize)
{
    var list = source.ToList();
    var pageCount = (list.Count + pageSize - 1) / pageSize;
    for (var pageNumber = 1; pageNumber <= pageCount; pageNumber++)
    {
        yield return GetPage(list, pageNumber, pageSize);
    }
}

It works, but is is very ineffcient. It iterates the collection from the start, each time you get a new page. A better option would be:

public static IEnumerable<IEnumerable<T>> PagesOf<T>(this IEnumerable<T> source, int pageSize)
{
    var list = source.ToList();
    var pageCount = (list.Count + pageSize - 1) / pageSize;

    var pageRange = Enumerable.Range(1, pageCount);
    return pageRange.Select((page, index) => list.Skip(index * pageCount).Take(pageCount));
}

This option only iterates all items only once, but if you need just a few pages, it iterates the items of all pages. The last option does not have that disadvantage:

public static IEnumerable<IEnumerable<T>> PagesOf<T>(this IEnumerable<T> source, int pageSize)
{
    var pageItems = new List<T>(pageSize);

    foreach (T item in source)
    {
        pageItems.Add(item);

        if (pageItems.Count >= pageSize)
        {
            yield return pageItems;
            pageItems = new List<T>(pageSize);
        }
    }
    if (pageItems.Count > 0)
    {
        yield return pageItems;
    }
}

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

About the author

I am a software architect at Roxit and also a C# Developer. My main interests in the area of ​​C# are LINQ and generics

Visit my personal homepage (Dutch) for more info about me.

Month List

Page List