Funky
Funky

Reputation: 13602

Paging through an IEnumerable

I have an IEnumerable object (IEnumerable<Class>) and I would like to retrieve a specified line from the object. So if I'm on page two I would like to select row two from the IEnumerable object and then pass it on to another class etc.

I'm a bit stuck at the moment, any ideas?

Upvotes: 9

Views: 10836

Answers (5)

user71030
user71030

Reputation: 417

An overload of the Take() method accepts a Range as the argument rather than a quantity, allowing you to specify the beginning and ending indices of the elements you want to retrieve. This eliminates the need for the compound Skip.Take approach shown in other answers.

For example:

.Take(0..2)

So you can do something like the following in order to page through an IEnumerable.

const int PageSize = 2000;
double totalPages = Math.Floor((double)myEnumerable.Count() / PageSize);
for (int currentPage = 0; currentPage <= totalPages; currentPage++)
{
    var pageOfData = myEnumerable.Take((PageSize * currentPage)..((PageSize * currentPage) + PageSize));
    // do work with current page of Data
}

Obviously there are a lot of different ways you can implement this, but it seems cleaner than the Skip.Take approach.

Upvotes: 0

Randy Minder
Randy Minder

Reputation: 48392

If I understand your requirements correctly, something like this paging mechanism should work:

int pageSize = 10;
int pageCount = 2;

iEnumerable.Skip(pageSize*pageCount).Take(pageSize);

This example shows 10 rows per page and a page number of 2. So, it will skip to page 2 and take the first row on that page.

Upvotes: 2

Timothy Baldridge
Timothy Baldridge

Reputation: 10653

Look at the functions .Take() and .Skip(). I normally do something like this:

IEnumerable<object> GetPage(IEnumerable<object> input, int page, int pagesize)
{
     return input.Skip(page*pagesize).Take(pagesize);
}

Upvotes: 19

Massimo Della Calce
Massimo Della Calce

Reputation: 416

I've implemented a dynamic solution in vb.net, i hope helpful:

 <Runtime.CompilerServices.Extension()>
    Public Function Paginate(Of T As {Class})(source As T, skip As Integer, take As Integer) As T
    If source IsNot Nothing AndAlso TypeOf source Is IEnumerable Then

        Dim chunk = (From c In DirectCast(source, IEnumerable)).Skip(skip).Take(take).ToList
        If chunk.Count = 0 Then Return Nothing

        Return AutoMapper.Mapper.Map(chunk, GetType(T), GetType(T))
    End If
    Return source
End Function

Upvotes: 0

dtb
dtb

Reputation: 217233

Assuming that pages and rows start at 1, and there is a fixed number of rows per page (say 10), you need to transform the page number and the row to an index as follows:

Page    1  1  1  1  1  1  1  1  1  1  2  2  2  2  2  2  2  2  2  2  3  3  3 ...
Row     1  2  3  4  5  6  7  8  9 10  1  2  3  4  5  6  7  8  9 10  1  2  3 ...
                                         ↓
Index   0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 ...

Code:

int page = 2;
int row = 2;

int rowsPerPage = 10;

IEnumerable<MyClass> source = ...

MyClass result = source.ElementAt((page - 1) * rowsPerPage + (row - 1));

So to get row 2 on page 2, you need to skip the first page (10 elements) and then take the second element (index 1 in that page).

Upvotes: 1

Related Questions