LINQ查询以识别系列中的片段

时间:2016-02-22 21:20:02

标签: c# linq

假设我有以下数组(我的序列都按升序排序,并包含正整数)

foreach()

我想写一个linq查询来选择被视为一个组的系列中的连续数字。所以,在上面的例子中我会得到{[1,2,3],[7,8,9],[15,16,17]}。

我可以编写一个foreach()序列,遍历每个元素,看看序列在哪里跳跃并在那里产生一个组。但有没有LINQ唯一的方法呢?我可以将我的Me.Name代码移动到一个新的扩展方法,所以我的代码仍然看起来像LINQy,但我想知道System.Linq中是否有任何可用的代码。

编辑:我创建了自己的扩展程序(如下所示),但internal class Sequence { public int Start { get; set; } public int End { get; set; } } internal static class EnumerableMixins { public static IEnumerable<Sequence> GroupFragments(this IEnumerable<int> sequence) { if (sequence.Any()) { var lastNumber = sequence.First(); var firstNumber = lastNumber; foreach(var number in sequence.Skip(1)) { if (Math.Abs(number - lastNumber) > 1) { yield return new Sequence() { Start = firstNumber, End = lastNumber }; firstNumber = lastNumber = number; } else { lastNumber = number; } } yield return new Sequence() { Start = firstNumber, End = lastNumber }; } } } 在答案中提出了一些非常聪明的内容。

{{1}}

2 个答案:

答案 0 :(得分:10)

找到这些岛屿的一个老技巧是减去索引和数值。结果将代表独特的群体。使用select重载包括索引:

var mySequence = new [] {1, 2, 3, 7, 8, 9, 15, 16, 17};

var groups = mySequence
    .Select((val,ind) => new{val, group = val - ind})
    .GroupBy(v=>v.group, v=>v.val)
    .Select(v=> v.ToList()).ToList();

(在这里使用ToList,但当然如果首选数组则可以使用ToArray)

答案 1 :(得分:1)

我迟到了,但无论如何我想分享这个想法。你也可以创建一个这样的迭代器:

public static class Extensions
{
    public static IEnumerable<IEnumerable<int>> ContinuousNumbers(this IEnumerable<int> source)
    {
        using (var e = source.GetEnumerator())
        {
            if (e.MoveNext())
            {
                var list = new List<int> { e.Current};
                int temp = e.Current;
                while (e.MoveNext())
                {
                    if (e.Current == temp+1)
                    {
                        list.Add(e.Current);
                        temp++;
                    }
                    else
                    {
                        yield return list;
                        list = new List<int> { e.Current};
                        temp = e.Current;
                    }
                }

                if (list.Count > 0)
                {
                    yield return list;
                }
            }
        }
    }
}

另一种变体可能是使用Aggregate扩展方法:

var result = mySequence.Aggregate(new List<List<int>>(),
                                   (r, current) =>
                                   {
                                       if ( r.Count==0  ||  (r.Last().Count>0 && r.Last().Last() != current-1))
                                           r.Add(new List<int> { current});
                                       else
                                           r.Last().Add(current);
                                       return r;
                                   });