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:

  1. 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;

    ReplyDelete
  2. 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 []

    ReplyDelete
  3. 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?

    ReplyDelete