I recently needed to group some objects, which is easy with GroupBy, but I also needed to enforce a maximum group size, as demonstrated by the following test.
public void Splits_Group_When_GroupSize_Greater_Than_MaxSize()
{
var items = new[] { "A1", "A2", "A3", "B4", "B5" };
var result = items.GroupByWithMaxSize(i => i[0], maxSize: 2);
Assert.True(result.ElementAt(0).SequenceEqual(new[] { "A1", "A2" }));
Assert.True(result.ElementAt(1).SequenceEqual(new[] { "A3" }));
Assert.True(result.ElementAt(2).SequenceEqual(new[] { "B4", "B5" }));
}
public static IEnumerable<IEnumerable<T>> GroupByWithMaxSize<T, TKey>(
this IEnumerable<T> source, Func<T, TKey> keySelector, int maxSize)
{
var originalGroups = source.GroupBy(keySelector);
foreach (var group in originalGroups)
{
if (group.Count() <= maxSize)
{
yield return group;
}
else
{
var regroups = group.Select((item, index) => new { item, index })
.GroupBy(g => g.index / maxSize);
foreach (var regroup in regroups)
{
yield return regroup.Select(g => g.item);
}
}
}
}