One of the great things about Linq is that it is so easy to extend. You just need to create an extension method whose argument is IEnumerable<T>
.
public namespace MyNamespace
{
public static class LinqExtensions
{
public static IEnumerable<List<T>> Batch<T>(this IEnumerable<T> source, int batchSize)
{
var batch = new List<T>();
foreach (T item in source)
{
batch.Add(item);
if (batch.Count == batchSize)
{
yield return batch;
batch = new List<T>();
}
}
if (batch.Count > 0)
yield return batch;
}
}
}
This example splits the items in an IEnumerable<T>
into lists of a fixed size, the last list containing the remainder of the items. Notice how the object to which the extension method is applied is passed in (argument source
) as the initial argument using the this
keyword. Then the yield
keyword is used to output the next item in the output IEnumerable<T>
before continuing with execution from that point (see yield keyword).
This example would be used in your code like this:
//using MyNamespace;
var items = new List<int> { 2, 3, 4, 5, 6 };
foreach (List<int> sublist in items.Batch(3))
{
// do something
}
On the first loop, sublist would be {2, 3, 4}
and on the second {5, 6}
.
Custom LinQ methods can be combined with standard LinQ methods too. e.g.:
//using MyNamespace;
var result = Enumerable.Range(0, 13) // generate a list
.Where(x => x%2 == 0) // filter the list or do something other
.Batch(3) // call our extension method
.ToList() // call other standard methods
This query will return even numbers grouped in batches with a size of 3: {0, 2, 4}, {6, 8, 10}, {12}
Remember you need a using MyNamespace;
line in order to be able to access the extension method.