Alastair Pitts Alastair Pitts - 7 months ago 50
C# Question

Can I improve these Pagination extension methods?

I've just written a couple of pagination extension methods and I was curious to know if there was any improvements I could make.

I'm pretty happy with the base pagination method, where you supply both the page size and page number (as seen below)

public static IEnumerable<T> Paginate<T>(this IEnumerable<T> source, int pageSize, int pageNumber)
if (pageSize == 0) throw new ArgumentOutOfRangeException("pageSize");
if (pageNumber == 0) throw new ArgumentOutOfRangeException("pageNumber");

return source.Skip(pageSize * (pageNumber - 1)).Take(pageSize);

but I was wondering if there was a better way to do the "auto" pagination, where it returns a

public static IEnumerable<IEnumerable<T>> Paginate<T>(this IEnumerable<T> source, int pageSize)
if (pageSize == 0) throw new ArgumentOutOfRangeException("pageSize");

var pageCount = (int)Math.Ceiling(source.Count() / (double)pageSize);

if (pageSize == 1)
pageCount = source.Count();

for (int i = 1; i <= pageCount; i++)
yield return source.Paginate(pageSize, i);

It seems a bit suspect to have to iterate twice (once for the count and once for the yield return.

Is there any obvious way I could improve these methods?


Take a look at MoreLinq Batch :-

Which is implemented as:

public static IEnumerable<IEnumerable<TSource>> Batch<TSource>(
              this IEnumerable<TSource> source, int size)
  TSource[] bucket = null;
  var count = 0;

  foreach (var item in source)
      if (bucket == null)
          bucket = new TSource[size];

      bucket[count++] = item;
      if (count != size)

      yield return bucket;

      bucket = null;
      count = 0;

  if (bucket != null && count > 0)
      yield return bucket.Take(count);