Home > Mobile >  Split list into sublists using value as the delimiter
Split list into sublists using value as the delimiter

Time:08-04

Almost every single programming language has a string split function:

foreach (var partition in "12304508".Split("0"))
{
    Console.WriteLine(partition);
}
// Output:
// 123
// 45
// 8

Is there any way to do the same but for a generic list instead of a string, i.e. something like:

int[] nums = new int[] {1, 2, 3, 0, 4, 5, 0, 8}; // can be any generic type instead of int
foreach (var partition in nums.SomeLinqFunctionHere(0))
{
    Console.WriteLine(partition);
}
// Expected output:
// int[]{1, 2, 3}
// int[]{4, 5}
// int[]{8}

What's the easiest way of doing that?

CodePudding user response:

Try the following:

public static class EnumerableExtensions
{
    public static IEnumerable<T[]> SplitEnumerable<T>(this IEnumerable<T> enumerable, T byValue)
    {
        return SplitEnumerable(enumerable, byValue, EqualityComparer<T>.Default);
    }

    public static IEnumerable<T[]> SplitEnumerable<T>(this IEnumerable<T> enumerable, T byValue, IEqualityComparer<T> comparer)
    {
        List<T> buffer = new List<T>();
        foreach (var v in enumerable)
        {
            if (comparer.Equals(v, byValue))
            {
                yield return buffer.ToArray();
                buffer.Clear();
            }
            else
            {
                buffer.Add(v);
            }
        }

        yield return buffer.ToArray();
    }
}

CodePudding user response:

This should work and is flexible in a way that you can split by conditions instead of only values:

public static IEnumerable<IList<T>> SplitBy<T>(this IEnumerable<T> sequence, Predicate<T> matchFilter)
{
    List<T> list = new List<T>();
    foreach(T item in sequence)
    {
        if (matchFilter(item))
        {
            yield return list;
            list = new List<T>();
        }
        else
        {
            list.Add(item);
        }
    }
    if (list.Any()) yield return list;
}

Use:

int[] nums = new int[] { 1, 2, 3, 0, 4, 5, 0, 8 }; // can be any generic type instead of int
foreach (var partition in nums.SplitBy(i => i == 0))
{
     Console.WriteLine(String.Join(",", partition));
}
  • Related