There is no 'performant' way to do this with the built in Linq operators that I am aware of. You could create your own extension method, though:
public static class EnumerableExtensions
{
public static IEnumerable<TResult> GroupWhile<TSource, TAccumulation, TResult>(
this IEnumerable<TSource> source,
Func<TAccumulation> seedFactory,
Func<TAccumulation, TSource, TAccumulation> accumulator,
Func<TAccumulation, bool> predicate,
Func<TAccumulation, IEnumerable<TSource>, TResult> selector)
{
TAccumulation accumulation = seedFactory();
List<TSource> result = new List<TSource>();
using(IEnumerator<TSource> enumerator = source.GetEnumerator())
{
while(enumerator.MoveNext())
{
if(!predicate(accumulator(accumulation, enumerator.Current)))
{
yield return selector(accumulation, result);
accumulation = seedFactory();
result = new List<TSource>();
}
result.Add(enumerator.Current);
accumulation = accumulator(accumulation, enumerator.Current);
}
if(result.Count > 0)
{
yield return selector(accumulation, result);
}
}
}
}
And then call it like this:
int limit = 10;
var groups =
records
.GroupWhile(
() => 0,
(a, x) => a + x,
(a) => a <= limit,
(a, g) => new { Total = a, Group = g });
The way it is currently written, if any single record exceeds that limit then that record is returned by itself. You could modify it to exclude records that exceed the limit or leave it as is and perform the exclusion with Where
.
This solution has O(n) runtime.