Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get Range of integers with linq

Tags:

.net

linq

I'm looking for a way to compute the range of a give set of number for example.

if I had H555,H567,H589,H590,H591,H592,H593,H594,H595,H596,H597

I would like output of H555,H567,H589-H597.

I have looked through relevant questions and can not find anything like what I'm looking for.

Thanks

like image 712
Jesse Avatar asked Sep 21 '10 16:09

Jesse


2 Answers

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);
like image 94
Jon Skeet Avatar answered Nov 13 '22 00:11

Jon Skeet


I think that Linq is really overhead here but if you want it here you are:

        int[] arr = { 555, 567, 589, 590, 591, 592, 593, 594, 595, 596, 597 };
        int gr = 0;
        var q = arr
            .Skip(1)
            .Select((x, i) => new { x, group = (x - arr[i]) == 1 ? gr : gr++ })
            .GroupBy( a => a.group)
            .Select(
                a => a.Count() == 1 
                    ? a.First().x.ToString() 
                    : string.Format("{0}-{1}", a.First().x, a.Last().x));
        foreach (var item in q)
        {
            Console.Write(item);
            Console.Write(", ");
        }
like image 35
Andrey Avatar answered Nov 12 '22 23:11

Andrey