Splitting LINQ query based on predicate

public static IEnumerable<IEnumerable<TSource>> Split<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate)
{
    List<TSource> group = new List<TSource>();
    foreach (TSource item in source)
    {
        if (predicate(item))
        {
            yield return group.AsEnumerable();
            group = new List<TSource>();
        }
        else
        {
            group.Add(item);
        }
    }
    yield return group.AsEnumerable();
}

If you're looking to avoid the extension method, you could always use:

var arr = new[] {"One", "Two", "Three", "Nine", "Four", "Seven", "Five"};

var result = arr.ToLookup(x => x.EndsWith("e"));

// result[true]  == One Three Nine Five
// result[false] == Two Four Seven

You should do this through an extension method (this method assumes you ignore the partitioned item):

/// <summary>Splits an enumeration based on a predicate.</summary>
/// <remarks>
/// This method drops partitioning elements.
/// </remarks>
public static IEnumerable<IEnumerable<TSource>> Split<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> partitionBy,
    bool removeEmptyEntries = false,
    int count = -1)
{
    int yielded = 0;
    var items = new List<TSource>();
    foreach (var item in source)
    {
        if (!partitionBy(item))
            items.Add(item);
        else if (!removeEmptyEntries || items.Count > 0)
        {
            yield return items.ToArray();
            items.Clear();

            if (count > 0 && ++yielded == count) yield break;
        }
    }

    if (items.Count > 0) yield return items.ToArray();
}

Tags:

C#

Linq