Add intersection to Range
It would be great if there was a way to do an intersection with ranges. I wrote a method recently to solve this but it gets complicated and doesn't solve for all edge cases.
The example I was using it for was getting the intersection of two date ranges. I was using it to calculate pricing discounts for overlapping dates for a reservation system.
I would propose something like:
(Date.new(2020, 04, 03)..Date.new(2020, 04, 20)) & (Date.new(2020, 04, 15)..Date.new(2020, 04, 30)) => Wed, 15 Apr 2020..Mon, 20 Apr 2020
There are a handful of array methods that you can just convert a range to and do on an arrays rather than the ranges themselves, like so:
(Date.new(2020, 04, 03)..Date.new(2020, 04, 20)).to_a & (Date.new(2020, 04, 15)..Date.new(2020, 04, 30)).to_a => [Wed, 15 Apr 2020, Thu, 16 Apr 2020, Fri, 17 Apr 2020, Sat, 18 Apr 2020, Sun, 19 Apr 2020, Mon, 20 Apr 2020]
There are a few issues with this however:
- Performance: creating the ranges into arrays and doing array calculations can me slower based on the span of the range.
- Returning a range: if you want to go back to a range, you need to convert the resulting array back to a range, which involves min and maxing the array and handling nil edge cases.
- Infinite ranges: Now that there are endless and beginless ranges added in ruby 2.6 and 2.7 respectively, you can not convert an infinite range to an array and therefore can't do an intersection without more complex logic.
I think the added infinite range support makes it a good reason to add range intersections since that is a feature you can't accomplish with just an array.
It looks like there was an Array#intersection alias added for Array#& recently. I would propose Range#& and Range#intersection to have parity with Array and Set methods.