Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting sets of integers into ranges using C#

Tags:

c#

algorithm

What's the most idiomatic way to convert a set of integers into a set of ranges?

E.g. given the set {0, 1, 2, 3, 4, 7, 8, 9, 11} I want to get { {0,4}, {7,9}, {11,11} } using C#

This question is already answered in C++ @ Solution in C++

like image 452
Novice Avatar asked Nov 10 '10 18:11

Novice


People also ask

How do you find the range of integers?

To find the range, first put all the numbers in order. Then subtract (take away) the lowest number from the highest.

What is range in C programming?

Below is the programming implementation of the int data type in C. Range: -2,147,483,648 to 2,147,483,647. Size: 2 bytes or 4 bytes.

What is the range of values that can be stored by INT datatype in C?

The INTEGER data type stores whole numbers that range from -2,147,483,647 to 2,147,483,647 for 9 or 10 digits of precision.

What is the range of 10 9 INT?

Use “int”. As its range is from -2^31 to +2^31. Around ~10^9. But in case of n~10^18.


2 Answers

This isn't very efficient, but it is idiomatic:

var nums = new HashSet<int>{0, 1, 2, 3, 4, 7, 8, 9, 11};
IEnumerable<Tuple<int, int>> ranges = Enumerable.Zip(
    nums.Where(n => !nums.Contains(n - 1)),
    nums.Where(n => !nums.Contains(n + 1)),
    Tuple.Create);

More efficient, assuming it's sorted:

public IEnumerable<Tuple<int, int>> GetContiguousRanges(IEnumerable<int> nums)
{
    int start = nums.First();
    int last = start - 1;
    foreach (int i in nums)
    {
        if (i != last + 1)
        {
            yield return Tuple.Create(start, last);
            start = i;
        }
        last = i;
    }
    yield return Tuple.Create(start, last);
}
like image 109
Alastair Maw Avatar answered Sep 22 '22 10:09

Alastair Maw


This should be a pretty straightforward transliteration from the post you mentioned. Make sure you put this code in a class somewhere, C# code has to be in a class. I'm assuming you are not very familiar with C#, so I'll do enough to show the similarities and differences, and hopefully you can handle the rest.

struct Range
{
    public Range (int start, int end) { this.start = start; this.end = end; }
    public int start;
    public int end;
}

public static void SetToRanges(Dictionary<int,bool> indices, List<Range> ranges) 
{
    Range r = new Range(int.MinValue, int.MaxValue);
    foreach (int i in indices.Keys)
    {
        // translate rest of code here
    }
    ranges.Add(r);
    return ranges;
}

For a more idiomatic soluiton, I would return an IEnumerable<Range>, so the "list" can be built and iterated simultaneously:

public static IEnumerable<Range> SetToRanges(Dictionary<int, bool> indices)
{
     // instead of "ranges.Add(r)", use "yield return r".
     // This returns multiple values in order from the function, that can
     // be iterated with "foreach (Range i in SetToRanges(foo))"
}
like image 41
luqui Avatar answered Sep 22 '22 10:09

luqui