Here is my suggestion for an extension method using iterators:
public static IEnumerable<IEnumerable<int>> GroupConsecutive(this IEnumerable<int> src) { var more = false; // compiler can't figure out more is assigned before use IEnumerable<int> ConsecutiveSequence(IEnumerator<int> csi) { int prevCurrent; do yield return (prevCurrent = csi.Current); while ((more = csi.MoveNext()) && csi.Current-prevCurrent == 1); } var si = src.GetEnumerator(); if (si.MoveNext()) { do // have to process to compute outside level yield return ConsecutiveSequence(si).ToList(); while (more); } }
I must say the Python algorithm is very impressive, here is a C# implementation of it:
public static IEnumerable<IEnumerable<int>> GroupConsecutive(this IEnumerable<int> iterable, Func<int,int> ordering = null) { ordering = ordering ?? (n => n); foreach (var tg in iterable .Select((e, i) => (e, i)) .GroupBy(t => t.i - ordering(t.e))) yield return tg.Select(t => t.e); }
Here is a C# one-line implementation of the Python algorithm:
public static IEnumerable<IEnumerable<int>> GroupConsecutive(this IEnumerable<int> iterable, Func<int,int> ordering = null) => iterable .Select((e, i) => (e, i)) .GroupBy( t => t.i - (ordering ?? (n => n))(t.e), (k,tg) => tg.Select(t => t.e));
NOTE: C# 8 with nullable annotation context enabled should use Func<int,int>? in both Python methods. You could also use ??= to assign ordering.
forloop be "pretty"? My guess is that a Linq solution would actually be "uglier" IMHO.