Michael0x2a
Michael0x2a

Reputation: 64208

Is there a "split list" method in c#?

In C#, calling the .Split method will split a string into an array of strings based on some character or string.

Is there an equivalent method for lists or arrays?

For example:

var foo = new List<int>() { 1, 2, 3, 0, 4, 5, 0, 6 };
var output = Split(foo, 0);
// produces { { 1, 2, 3 }, { 4, 5 }, { 6 } }

This is what I have so far -- is there a cleaner or more eloquent way of accomplishing the same task?

IEnumerable<IEnumerable<T>> Split<T>(IEnumerable<T> list, T divider)
{
    var output = new List<List<T>>();
    var temp = new List<T>();
    foreach ( var item in list )
    {
        if (item.Equals(divider))
        {
            output.Add(temp);
            temp = new List<T>();
        }
        else
        {
            temp.Add(item);
        }
    }

    output.Add(temp);
    return output;
}

Edit:

It just occurred to me that my version will split the list only by a single element, whereas string.Split can split using either a single character, or an arbitrary string.

Just for the sake of completeness, what would be the best way to implement that?

Upvotes: 7

Views: 473

Answers (3)

Shahed
Shahed

Reputation: 898

Don't know of any built-in function. However, I would consider doing this:

public static IEnumerable<List<int>> Split(List<int> list, int delimiter)
{
    var start = 0;
    foreach (var end in list.FindAll(x => x == delimiter).Select(splitter => list.IndexOf(splitter, start)))
    {
        yield return list.GetRange(start, end - start);

        start = end + 1;
    }

    if (start <= list.Count)
    {
        yield return list.GetRange(start, list.Count - start);
    }
}

Upvotes: 0

Alexei Levenkov
Alexei Levenkov

Reputation: 100545

No, there is no special existing method in the framework to split sequence.

You code is reasonable.

Routes to improve/change:

  • You may be able to use yield return instead of adding to output to gain some lazy evaluation.
  • With even more interesting code you can make inner lists lazy too (which may be important if incoming sequence is not bound/too long segments).
  • And you can using Aggregate if you want to show off single statement code...

Upvotes: 2

I4V
I4V

Reputation: 35363

No built-in equivalent, but a lazy-evaluated one would be

IEnumerable<IEnumerable<T>> Split<T>(IEnumerable<T> list, T divider)
{
    var temp = new List<T>();
    foreach (var item in list)
    {
        if (!item.Equals(divider))
        {
            temp.Add(item);
        }
        else
        {
            yield return temp;
            temp = new List<T>();
        }
    }

    if(temp.Count>0) yield return temp;
}

Upvotes: 8

Related Questions