Well, I'd do something like this:
public sealed class Range
{
public int Low { get; private set; }
public int High { get; private set; }
public Range(int low, int high)
{
this.Low = low;
this.High = high;
}
}
Then (completely untested, may not even compile, but hopefully you'll get the drift):
public static IEnumerable<Range> FindRanges(IEnumerable<int> values)
{
using (IEnumerator<int> iterator = values.GetEnumerator())
{
if (!iterator.MoveNext())
{
yield break;
}
int low = iterator.Current;
int high = low;
while (iterator.MoveNext())
{
int next = iterator.Current;
if (next > high + 1)
{
// Previous range (or possibly single value) has finished
yield return new Range(low, high);
low = next;
}
high = next;
}
// Yield trailing range
yield return new Range(low, high);
}
}
I don't think this is particularly easy to do using straight LINQ, to be honest.
EDIT: To adapt this now that everything starts with H, just use:
var numbers = strings.Select(x => int.Parse(x.Substring(1));
var ranges = FindRanges(numbers);
var rangeStrings = ranges.Select(r => r.High == r.Low
? "H" + r.Low : "H" + r.Low + "-" + r.High);
var result = string.Join(",", rangeStrings);