Grouping sequential blocks of data using LINQ – GroupWhile

A few days ago, I was required to group sequential blocks of data into separate ‘chunks’. Imagine the below sequence of integers

124356791011

We’d want to create a group 1 and 2, but 4 should be in a separate group as it’s missing 3. So the groups would look like this

A-B-C-D-E
12-4-3-567-91011

I decided to write an extension method that would do this, but also be much more generic and keep it as flexible as possible. In the broadest sense, all we need to do is add items to a group while a condition is True, then as soon as the condition is False, create a new group and carry on.

public static IEnumerable<IEnumerable<T>> GroupWhile<T>(this IEnumerable<T> source, Func<T, T, bool> condition)
{
    T previous = source.First();
    var list = new List<T>() { previous };


    foreach (T item in source.Skip(1))
    {
        if (condition(previous, item) == false)
        {
            yield return list;
            list = new List<T>();
        }
        list.Add(item);
        previous = item;
    }

    yield return list;
}

The use of this is as below

items.GroupWhile((x, y) => y.Sequence - x.Sequence == 1);

As you can imagine you could put any logic inside the lambda expression – you could group until a certain flag is set like the below

items.GroupWhile((x, y) => !x.EndOfGroup);

I haven’t found that I nee to use this often – but it’s a nice tool to add to your library. Note that it will not work for LINQ to SQL of course, as it is unable to translate this code into a SQL query