Thursday, January 7, 2010

Grouping consecutive integers in C#

Quick post: an extension method to group consecutive integers:

/// <summary>
/// Groups consecutive integers. Requires asc-ordered list
/// </summary>
/// <param name="list">ASC-ordered list of integers</param>
/// <returns></returns>
public static IEnumerable<IEnumerable<int>> GroupConsecutive(this IEnumerable<int> list) {
    var group = new List<int>();
    foreach (var i in list) {
        if (group.Count == 0 || i - group[group.Count - 1] <= 1)
            group.Add(i);
        else {
            yield return group;
            group = new List<int> {i};
        }
    }
    yield return group;
}

Sample usage:

var groups = new[] {1, 2, 4, 5, 6, 9}.GroupConsecutive();
foreach (var g in groups)
    Console.WriteLine("group: {0}", string.Join(",", g.Select(x => x.ToString()).ToArray()));

which prints out:

group: 1,2
group: 4,5,6
group: 9

5 comments:

Anonymous said...

Very cool :)

Anonymous said...

liked it, thanks

Terrence Jones said...

Handy routine; thanks. I added the following to the beginning of the method to better support an empty input list. Otherwise, an empty group is returned.

if (list.Count() == 0)
yield break;

Vasily said...

F# version :)

let groupConsecutive xs =
List.foldBack (fun x acc ->
match acc, x with
| [], _ -> [[x]]
| (h :: t) :: rest, x when h - x <= 1 -> (x :: h :: t) :: rest
| acc, x -> [x] :: acc) xs []

Unknown said...

So how can we group only 4,5,6 and others not?

Question is this groups every element even if they are alone, but is there a way to prevent creating single groups and create a consecutive group if group count is min 3?? (Like 4,5,6 but not 1,2 or 9)

Any idea?