You can use List.GetRange:
for(var i = 0; i < source.Count; i += chunkSize)
{
List items = source.GetRange(i, Math.Min(chunkSize, source.Count - i));
}
Although not at fast as Array.Copy, I think it looks cleaner:
var list = Enumerable.Range(0, 723748).ToList();
var stopwatch = new Stopwatch();
for (int n = 0; n < 5; n++)
{
stopwatch.Reset();
stopwatch.Start();
for(int i = 0; i < list.Count; i += 100)
{
List c = list.GetRange(i, Math.Min(100, list.Count - i));
}
stopwatch.Stop();
Console.WriteLine("List.GetRange: " + stopwatch.ElapsedMilliseconds.ToString());
stopwatch.Reset();
stopwatch.Start();
for (int i = 0; i < list.Count; i += 100)
{
List c = list.Skip(i).Take(100).ToList();
}
stopwatch.Stop();
Console.WriteLine("Skip/Take: " + stopwatch.ElapsedMilliseconds.ToString());
stopwatch.Reset();
stopwatch.Start();
var test = list.ToArray();
for (int i = 0; i < list.Count; i += 100)
{
int length = Math.Min(100, list.Count - i);
int[] c = new int[length];
Array.Copy(test, i, c, 0, length);
}
stopwatch.Stop();
Console.WriteLine("Array.Copy: " + stopwatch.ElapsedMilliseconds.ToString());
stopwatch.Reset();
stopwatch.Start();
List> chunks = list
.Select((s, i) => new { Value = s, Index = i })
.GroupBy(x => x.Index / 100)
.Select(grp => grp.Select(x => x.Value).ToList())
.ToList();
stopwatch.Stop();
Console.WriteLine("LINQ: " + stopwatch.ElapsedMilliseconds.ToString());
}
Results in milliseconds:
List.GetRange: 1
Skip/Take: 9820
Array.Copy: 1
LINQ: 161
List.GetRange: 9
Skip/Take: 9237
Array.Copy: 1
LINQ: 148
List.GetRange: 5
Skip/Take: 9470
Array.Copy: 1
LINQ: 186
List.GetRange: 0
Skip/Take: 9498
Array.Copy: 1
LINQ: 110
List.GetRange: 8
Skip/Take: 9717
Array.Copy: 1
LINQ: 148