Interesting problem. I decided for readability to have a class representing a range:
class NumberRange
{
public int Start { get; set;}
public int End { get; set;}
public override string ToString()
{
return Start == End ? Start.ToString() : String.Format("{0}-{1}",Start,End);
}
}
and an extension method to turn an IEnumerable of ordered integers into an IEnumerable of ranges:
public static IEnumerable<NumberRange> ToRanges(this IEnumerable<int> numbers)
{
NumberRange currentRange = null;
foreach(var number in numbers)
{
if (currentRange == null)
currentRange = new NumberRange() { Start = number, End = number };
else if (number == currentRange.End + 1)
currentRange.End = number;
else
{
yield return currentRange;
currentRange = new NumberRange { Start = number, End = number };
}
}
if (currentRange != null)
{
yield return currentRange;
}
}
And with that in place you can get the ranges and format them however you want:
String.Join(",",
new int[] { 1,2,3,5,7,8,9,11 }
.ToRanges()
.Select(r => r.ToString()))