HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpModerate

Compact a comma delimited number list into ranges

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
numbercommadelimitedintorangeslistcompact

Problem

I'm looking for a clever way to do the following operation:

Take a list of numbers:

1, 2, 3, 4, 5, 12, 13, 14, 19

and compact it into a string like so:

1-5, 12-14, 19

With the following rule: only compress into a range (i.e. use a dash) when the count of numbers in the range is 3 or more.

I.e.: 1, 2, 4, 5 would result in: 1, 2, 4, 5 and NOT: 1-2, 4-5

This is my implementation, but I feel like it could be improved upon greatly:

public string CompactNumberRanges(IEnumerable numbers, 
                                   int requiredRangeCount)
 {
     if (requiredRangeCount  e).ToArray();

     StringBuilder b = new StringBuilder();

     for (int i = 0; i = requiredRangeCount)
         {
             b.Append(", ").AppendFormat("{0}-{1}", cv, sorted[i + count - 1]);

             i += count - 1;
         }
     }

     return b.ToString().Trim(',', ' '); ;
 }


As an example:

List numbers = new List
    (
        new int[] { 1, 2, 3, 4, 5, 12, 13, 14, 19 }
    );

Console.WriteLine(CompactNumberRanges(numbers, 3));
//  output: 1-5, 12-14, 19


I have this working fine, I'm really just looking to find better ways to do the same operation because I think it's a fun one.

Solution

You could calculate a value to group on, i.e. number - index. All consecutive numbers have the same value:

index  number  number - index
-----  ------  --------------
  0       1          1
  1       2          1
  2       3          1
  3       4          1
  4       5          1
  5      12          7
  6      13          7
  7      14          7
  8      19         11


Then you just check how many items there is in each group to determine if it should be a range.

Example:

List numbers = new List { 1, 2, 3, 4, 5, 12, 13, 14, 19 };

List items = numbers
  .Select((n,i) => new { number = n, group = n - i })
  .GroupBy(n => n.group)
  .Select(g =>
    g.Count() >= 3 ?
      g.First().number + "-" + g.Last().number
    :
      String.Join(", ", g.Select(x => x.number))
  )
  .ToList();

Console.WriteLine(String.Join(", ", items));


Output:

1-5, 12-14, 19

Code Snippets

index  number  number - index
-----  ------  --------------
  0       1          1
  1       2          1
  2       3          1
  3       4          1
  4       5          1
  5      12          7
  6      13          7
  7      14          7
  8      19         11
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 12, 13, 14, 19 };

List<string> items = numbers
  .Select((n,i) => new { number = n, group = n - i })
  .GroupBy(n => n.group)
  .Select(g =>
    g.Count() >= 3 ?
      g.First().number + "-" + g.Last().number
    :
      String.Join(", ", g.Select(x => x.number))
  )
  .ToList();

Console.WriteLine(String.Join(", ", items));
1-5, 12-14, 19

Context

StackExchange Code Review Q#90072, answer score: 18

Revisions (0)

No revisions yet.