C#/ Linq获取相邻的集合

我有一个有序列表,如0,1,2,6,7,10

我想得到数字增加1的集合。我想要第一个数字和计数或系列。

所以我会得到
start = 0,count = 3
start = 6,count = 2
start = 10,count = 1

我怎么能在C#中做到这一点?

答案是我认为最好的方式。 对我来说,可读性比性能更重要。

定义一个简单的类来保存结果:

private class Set { public int Start = 0; public int Count = 0; } 

你可以使用这样的方法:

  private static IEnumerable GetSets(List src) { List rtn = new List(); int previous = int.MaxValue; foreach (int i in src) { if (i == previous + 1) { rtn[rtn.Count - 1].Count += 1; } else { rtn.Add(new Set() { Start = i, Count = 1 }); } previous = i; } return rtn; } 

我并不热衷于int.MaxValue的神奇价值,但它在第一次迭代时节省了额外的逻辑。

正确调用GetSets(new List() { 0, 1, 2, 6, 7, 10 })会得到您需要的结果。

试试这个(在LinqPad中作为“C#语句”)

 var nums = new [] {0, 1, 2, 6, 7, 10}; Debug.Assert(nums.All(i => i >= 0)); Debug.Assert(nums.Zip(nums.Skip(1), (n1, n2) => (n1 < n2)).All(_ => _)); var @group = 0; nums.Zip(nums.Skip(1).Concat(new [] {nums.Last ()}), (n1, n2) => Tuple.Create( n1, (n2 - n1) == 1 ? @group : @group++)) .GroupBy (t => t.Item2) .Select (g => new {Group = g.Select(x => x.Item1), Count = g.Count()}) .Dump() ; 

也许使用扩展方法更简洁

 public static IEnumerable> GetConsecutiveCollections(this IEnumerable source) { var list = new List(); var start = source.Min() - 1; foreach (var i in source) { if (i == start + 1) { list.Add(i); start = i; } else { var result = list.ToList(); list.Clear(); list.Add(i); start = i; yield return result; } } yield return list; } 

然后以这种方式创建结果:

 var result = x.GetConsecutiveCollections() .Select(c => new { Start = c.Min(), Count = c.Count()}); 

产量怎么样?

 class GetSetsWithAdjacent { public struct CountEm { public int start; public int count; override public string ToString() { return string.Format("start={0}, count={1}", this.start, this.count); } } static public IEnumerable GenCount(int[] inputs) { return GenCount(((IEnumerable)inputs).GetEnumerator()); } static public IEnumerable GenCount(IEnumerator inputs) { if (inputs.MoveNext()) { CountEm result = new CountEm {start = inputs.Current, count = 1 }; while (inputs.MoveNext()) { if (result.start + result.count == inputs.Current) { result.count += 1; } else { yield return result; result = new CountEm { start = inputs.Current, count = 1 }; } } yield return result; } } } class StackOverflow { private static void Test_GetSetsWithAdjacent() { // http://stackoverflow.com/questions/7064157/c-linq-get-sets-with-adjacent int[] inputs = { 0, 1, 2, 6, 7, 10 }; foreach (GetSetsWithAdjacent.CountEm countIt in GetSetsWithAdjacent.GenCount(inputs)) { Console.WriteLine(countIt); } } internal static void Test() { Test_GetSetsWithAdjacent(); } }