I am attempting to split a list into a series of smaller lists.
My Problem: My function to split lists doesn\'t split them into lists of the correct
Based on Dimitry Pavlov answere I would remove .ToList(). And also avoid the anonymous class.
Instead I like to use a struct which does not require a heap memory allocation. (A ValueTuple would also do job.)
public static IEnumerable> ChunkBy(this IEnumerable source, int chunkSize)
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
if (chunkSize <= 0)
{
throw new ArgumentOutOfRangeException(nameof(chunkSize), chunkSize, "The argument must be greater than zero.");
}
return source
.Select((x, i) => new ChunkedValue(x, i / chunkSize))
.GroupBy(cv => cv.ChunkIndex)
.Select(g => g.Select(cv => cv.Value));
}
[StructLayout(LayoutKind.Auto)]
[DebuggerDisplay("{" + nameof(ChunkedValue.ChunkIndex) + "}: {" + nameof(ChunkedValue.Value) + "}")]
private struct ChunkedValue
{
public ChunkedValue(T value, int chunkIndex)
{
this.ChunkIndex = chunkIndex;
this.Value = value;
}
public int ChunkIndex { get; }
public T Value { get; }
}
This can be used like the following which only iterates over the collection once and also does not allocate any significant memory.
int chunkSize = 30;
foreach (var chunk in collection.ChunkBy(chunkSize))
{
foreach (var item in chunk)
{
// your code for item here.
}
}
If a concrete list is actually needed then I would do it like this:
int chunkSize = 30;
var chunkList = new List>();
foreach (var chunk in collection.ChunkBy(chunkSize))
{
// create a list with the correct capacity to be able to contain one chunk
// to avoid the resizing (additional memory allocation and memory copy) within the List.
var list = new List(chunkSize);
list.AddRange(chunk);
chunkList.Add(list);
}