I've written some code to group a list of items into arbitrarily sized buckets. If the items are all the same and the and the count is a multiple of the bucket size a single bucket is returned, if the items are different then they are grouped into buckets of a given size.
For example, with a bucket size of 3:
1,2 => [1,2]
1,2,3,4,5 => [1,2,3][4,5]
1,1,1,1,1,1 => [1,1,1,1,1,1]
1,1,1,1,1 => [1,1,1][1,1]
To achieve this I've written the following .Net extension method:
public static IEnumerable<IList<T>> GroupBySize<T>(this IEnumerable<T> source, int groupSize, Func<T, T, bool> comparer)
{
var result = new List<List<T>>();
if (source.IsNullOrEmpty())
return result;
List<T> currentGroup = null;
for (var i = groupSize; i <= source.Count(); i += groupSize)
{
var possibleGroup = source.Slice(i - groupSize, groupSize);
if (possibleGroup.All(x => comparer(x, possibleGroup.First())))
{
if (currentGroup == null)
{
currentGroup = new List<T>();
result.Add(currentGroup);
}
currentGroup.AddRange(possibleGroup);
}
else
{
currentGroup = new List<T>();
currentGroup.AddRange(possibleGroup);
result.Add(currentGroup);
currentGroup = null;
}
}
var remainingItems = source.Count() % groupSize;
if (remainingItems > 0)
{
result.Add(source.Slice(source.Count() - remainingItems, remainingItems).ToList());
}
return result;
}
public static IEnumerable<T> Slice<T>(this IEnumerable<T> source, int start, int count)
{
return source.Skip(start).Take(count);
}
public static bool IsNullOrEmpty<T>(this IEnumerable<T> items)
{
// Taken from :http://haacked.com/archive/2010/06/10/checking-for-empty-enumerations.aspx
return items == null || !items.Any();
}
The code passes the tests I've written, but it all (including the method name) feels a bit clunky.
How could this be improved?
1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1
and why? \$\endgroup\$