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++
To find the range, first put all the numbers in order. Then subtract (take away) the lowest number from the highest.
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.
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.
Use “int”. As its range is from -2^31 to +2^31. Around ~10^9. But in case of n~10^18.
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);
}
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))"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With