Split Array By Values In Sequence [duplicate]

2020-01-19 07:35发布

Is there an easy (linq?) way to split an int array into new arrays based off unbroken numerical sequences? For example given this pseudo code:

[Fact]
public void ArraySpike()
{
   var source = new[] {1, 2, 3, 7, 8, 9, 12, 13, 24};

   var results = SplitArray(source);

    Assert.True(results[0] == new[] {1, 2, 3});
    Assert.True(results[1] == new[] {7, 8, 9}); 
    Assert.True(results[2] == new[] {12, 13}); 
    Assert.True(results[3] == new[] {24}); 
}

public int[][] SplitArray(int[] source)
{
    return source.???   
}

标签: c# arrays linq
2条回答
放我归山
2楼-- · 2020-01-19 07:43

This can work with the linq extension Aggregate. My seeding is not very elegant but that is easy enough to change. The results variable will contain the array of arrays and they are actually of type List<T> because that way they can be easily grown in the function where an array [] is always of fixed size.

This also assumes the source is already ordered and unique, if that is not the case add .OrderBy(x => x).Distinct()

var source = new[] { 1, 2, 3, 7, 8, 9, 12, 13, 24 };
var results = new List<List<int>>{new List<int>()};

var temp = source.Aggregate(results[0], (b, c) =>
{
    if (b.Count > 0 && b.Last() != c - 1)
    {
        b = new List<int>();
        results.Add(b);
    }
    b.Add(c);
    return b;
});
查看更多
时光不老,我们不散
3楼-- · 2020-01-19 08:04

I dug up this extension method from my personal collection:

public static IEnumerable<IEnumerable<T>> GroupConnected<T>(this IEnumerable<T> list, Func<T,T,bool> connectionCondition)
{
    if (list == null)
    {
        yield break;
    }
    using (var enumerator = list.GetEnumerator())
    {
        T prev = default(T);
        var temp = new List<T>();
        while (enumerator.MoveNext())
        {
            T curr = enumerator.Current;
            {
                if(!prev.Equals(default(T)) && !connectionCondition(prev, curr))
                {
                    yield return temp;
                    temp = new List<T>();
                }
                temp.Add(curr);
            }
            prev = curr;
        }
        yield return temp;
    }
}

It solves the problem in a more general sense: split up a sequence in subsequences of elements that are "connected" somehow. It traverses the sequence and collects each element in a temporary list until the next item isn't "connected". It then returns the temporary list and begins a new one.

Your array elements are connected when they have a difference of 1:

var results = source.GroupConnected((a,b) => b - a == 1);
查看更多
登录 后发表回答