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);