CSharp · Console
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var a = Enumerable.Range(0, 11).ToArray();
Console.Write($"Batched list:\n\t");
Console.WriteLine(a.Batch(3).Select(i => i.Join(",")).Join(";"));
Console.Write($"First from each batch:\n\t");
Console.WriteLine(a.Batch(3).Select(i => i.First()).Join(","));
Console.Write($"Second from each batch:\n\t");
Console.WriteLine(a.Batch(3).Select(i => i.Skip(1).First()).Join(","));
// This still fails!
// Console.WriteLine(a.Batch(3).ToList().Select(i => i.Join(",")).Join(";"));
Console.Write($"Number of batches:\n\t");
Console.WriteLine(a.Batch(3).Count());
Console.Write($"Number of full batches:\n\t");
Console.WriteLine(a.Batch(3).Where(i => i.Count() == 3).Count());
Console.Write($"Buffering to access prior batches:\n\t");
Console.WriteLine(a.Batch(3).Buffer().Last().Join(","));
}
}
public static class BatchLinq
{
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int size)
{
if (source == null)
throw new ArgumentNullException("source");
if (size <= 0)
throw new ArgumentOutOfRangeException("size", "Must be greater than zero.");
using (var enumerator = source.GetEnumerator())
while (enumerator.MoveNext())
{
int i = 0;
// Batch is a local iterator function closing over `i` and
// `enumerator` that executes the inner batch enumeration
IEnumerable<T> Batch()
{
do yield return enumerator.Current;
while (++i < size && enumerator.MoveNext());
}
yield return Batch();
// discard skipped items
while (++i < size && enumerator.MoveNext());
}
}
public static IEnumerable<IReadOnlyList<T>> Buffer<T>(this IEnumerable<IEnumerable<T>> batched) => batched.Select(e => e.ToList());
public static string Join<T>(this IEnumerable<T> s, string j)
{
return string.Join(j, s.ToArray());
}
}