C # / Linq get sets with adjacent

I have an ordered list, e.g. 0,1,2, 6,7, 10

I want to get sets where numbers increase by 1. I want the first number and the number or series.

So, I would get start = 0, count = 3
start = 6, count = 2
start = 10, count = 1

How can I do this in C #?

The answer to what I feel is the most enjoyable way. Readability is more important than performance to me.

+6
source share
4 answers

Defining a simple class for storing results:

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

You can use this method:

  private static IEnumerable<Set> GetSets(List<int> src) { List<Set> rtn = new List<Set>(); 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; } 

I'm not fond of the magic value of int.MaxValue , but it retains additional logic around the first iteration.

Calling GetSets(new List<int>() { 0, 1, 2, 6, 7, 10 }) correctly gives the desired result.

+6
source

Try this (like "C # Statement" in LinqPad

 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() ; 
+2
source

It might be better to use the extension method

 public static IEnumerable<IEnumerable<int>> GetConsecutiveCollections(this IEnumerable<int> source) { var list = new List<int>(); 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; } 

And then create your result as follows:

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

How about a crop?

 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<CountEm> GenCount(int[] inputs) { return GenCount(((IEnumerable<int>)inputs).GetEnumerator()); } static public IEnumerable<CountEm> GenCount(IEnumerator<int> 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(); } } 
0
source

Source: https://habr.com/ru/post/895053/


All Articles