使用LINQ拆分数组

时间:2014-01-16 09:41:20

标签: c# linq list

假设我有一个列表

var listOfInt = new List<int> {1, 2, 3, 4, 7, 8, 12, 13, 14}

如何使用LINQ获取列表列表,如下所示:

{{1, 2, 3, 4}, {7, 8}, {12, 13, 14}}

所以,我必须取连续值并将它们分组到列表中。

4 个答案:

答案 0 :(得分:3)

这适用于已排序和未排序的列表:

var listOfInt = new List<int> { 1, 2, 3, 4, 7, 8, 12, 13 };
int index = 0;
var result = listOfInt.Zip(listOfInt
                            .Concat(listOfInt.Reverse<int>().Take(1))
                            .Skip(1), 
                            (v1, v2) => 
                            new 
                            { 
                                V = v1, 
                                G = (v2 - v1) != 1 ? index++ : index
                            })
                        .GroupBy(x => x.G, x => x.V, (k, l) => l.ToList())
                        .ToList();

外部index正在构建具有1值差异的连续组的索引。那么你可以简单地GroupBy关于这个索引。

为了澄清解决方案,以下是此集合在没有分组(GroupBy注释)的情况下的外观:

enter image description here

答案 1 :(得分:3)

您可以创建扩展方法(我省略了源检查),它将迭代源并创建连续项组。如果source中的下一个项目不是连续的,则会产生当前组:

public static IEnumerable<List<int>> ToConsecutiveGroups(
    this IEnumerable<int> source)
{
    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            yield break;
        }
        else
        {                    
            int current = iterator.Current;
            List<int> group = new List<int> { current };

            while (iterator.MoveNext())
            {
                int next = iterator.Current;
                if (next < current || current + 1 < next)
                {
                    yield return group;
                    group = new List<int>();                            
                }

                current = next;
                group.Add(current);
            }

            if (group.Any())
                yield return group;
        }                
    }
}

用法很简单:

var listOfInt = new List<int> { 1, 2, 3, 4, 7, 8, 12, 13, 14 };
var groups = listOfInt.ToConsecutiveGroups();

结果:

[
  [ 1, 2, 3, 4 ],
  [ 7, 8 ],
  [ 12, 13, 14 ]
]

更新:这是此扩展方法的通用版本,它接受谓词以验证是否应将两个值视为连续值:

public static IEnumerable<List<T>> ToConsecutiveGroups<T>(
    this IEnumerable<T> source, Func<T,T, bool> isConsequtive)
{
    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            yield break;
        }
        else
        {                    
            T current = iterator.Current;
            List<T> group = new List<T> { current };

            while (iterator.MoveNext())
            {
                T next = iterator.Current;
                if (!isConsequtive(current, next))
                {
                    yield return group;
                    group = new List<T>();                            
                }

                current = next;
                group.Add(current);
            }

            if (group.Any())
                yield return group;
        }                
    }
}

用法很简单:

var result = listOfInt.ToConsecutiveGroups((x,y) => (x == y) || (x == y - 1));

答案 2 :(得分:2)

假设您的输入按顺序,以下内容将起作用:

var grouped = input.Select((n, i) => new { n, d = n - i }).GroupBy(p => p.d, p => p.n);

如果您的输入是例如,则无效{ 1, 2, 3, 999, 5, 6, 7 }

你会得到{ { 1, 2, 3, 5, 6, 7 }, { 999 } }

答案 3 :(得分:0)

这有效:

var results =
    listOfInt
        .Skip(1)
        .Aggregate(
            new List<List<int>>(new [] { listOfInt.Take(1).ToList() }),
            (a, x) =>
            {
                if (a.Last().Last() + 1 == x)
                {
                    a.Last().Add(x);
                }
                else
                {
                    a.Add(new List<int>(new [] { x }));
                }
                return a;
            });

我得到了这个结果:

results