Search code examples
c#algorithmlinqlist

LINQ to find series of consecutive numbers


I have a list of integers. I want to find all runs of consecutive numbers on that list, defined by the start index and length. So for example, for input list of [1,2,3,5,7,8], the output would be [{1,3}, {5,1}, {7,2}]. This is easy enough to do using a loop, something like this (untested pseudocode):

for(i=1, i < maxNum; i++)
{
  number = list[i];
  previousNumber = list[i-1];
  if(number - previousNumber == 1)
  {
    runLength++;
  }
  else
  {
    result.Add(startingNumber, runLength);
    runLength = 1;
    startingNumber = number;
  }
}

But I thought it would be possible to do using LINQ. Any ideas how to do that?


Solution

  • A linqish way can be writing an extension method GroupWhile like below (All checks omitted. not optimized to understand easily.)

    int[] list = new int[] { 1, 2, 3, 5, 7, 8 };
    var result = list.GroupWhile((x, y) => y - x == 1)
                     .Select(x => new {i = x.First(), len = x.Count()  })
                     .ToList();
    

    public static IEnumerable<IEnumerable<T>> GroupWhile<T>(this IEnumerable<T> seq, Func<T,T,bool> condition)
    {
        T prev = seq.First();
        List<T> list = new List<T>() { prev };
    
        foreach(T item in seq.Skip(1))
        {
            if(condition(prev,item)==false)
            {
                yield return list;
                list = new List<T>();
            }
            list.Add(item);
            prev = item;
        }
    
        yield return list;
    }
    

    TODO: use IGrouping :)