提示するコードは、他の人が指摘したように、リスト内の項目を 1 回だけ反復します。
ただし、これでは 1 ページ分のアイテムしか表示されません。複数のページを処理している場合は、そのコードをページごとに 1 回呼び出す必要があります (どこかで をインクリメントする必要があるためですよねcurrentPage
?)。
つまり、次のようなことをしている必要があります。
for (int currentPage = 0; currentPage < numPages; ++currentPage)
{
foreach (var item in items.Skip(currentPage*itemsPerPage).Take(itemsPerPage))
{
//Do stuff
}
}
これを行うと、シーケンスを複数回 (各ページに 1 回) 反復することになります。最初の反復は最初のページの終わりまでしか進みませんが、次は 2 ページ目の最初から最後まで ( と を介して)反復し、次は最初から最後まで反復します。 3ページ目。等々。Skip()
Take()
これを回避するには、データをバッチに分割する拡張メソッドをIEnumerable<T>
記述できます (これは、データを「ページ」に「ページ分割」するとも言えます)。
IEnumerable の IEnumerable を提示するだけでなく、次のように、クラス内の各バッチをラップして、バッチ内のアイテムと共にバッチ インデックスを提供する方が便利な場合があります。
public sealed class Batch<T>
{
public readonly int Index;
public readonly IEnumerable<T> Items;
public Batch(int index, IEnumerable<T> items)
{
Index = index;
Items = items;
}
}
public static class EnumerableExt
{
// Note: Not threadsafe, so not suitable for use with Parallel.Foreach() or IEnumerable.AsParallel()
public static IEnumerable<Batch<T>> Partition<T>(this IEnumerable<T> input, int batchSize)
{
var enumerator = input.GetEnumerator();
int index = 0;
while (enumerator.MoveNext())
yield return new Batch<T>(index++, nextBatch(enumerator, batchSize));
}
private static IEnumerable<T> nextBatch<T>(IEnumerator<T> enumerator, int blockSize)
{
do { yield return enumerator.Current; }
while (--blockSize > 0 && enumerator.MoveNext());
}
}
この拡張メソッドはデータをバッファリングせず、一度だけ反復します。
この拡張メソッドを使用すると、アイテムをまとめて読みやすくなります。この例は、1 ページのアイテムのみを反復する OP の例とは異なり、すべてのページのすべてのアイテムを列挙することに注意してください。
var items = Enumerable.Range(10, 50); // Pretend we have 50 items.
int itemsPerPage = 20;
foreach (var page in items.Partition(itemsPerPage))
{
Console.Write("Page " + page.Index + " items: ");
foreach (var i in page.Items)
Console.Write(i + " ");
Console.WriteLine();
}