[ruby-core:126019] [Ruby Feature#16757] Add intersection to Range
Issue #16757 has been updated by matz (Yukihiro Matsumoto). Status changed from Open to Closed Closing this issue. We have accepted `Range#clamp` (#22175), which covers the main use case here: restricting a range to given bounds. For overlapping ranges it gives the same result as an intersection would. I do not want to add a general `Range#intersection` (or `Range#&`). It raises semantic questions with no obviously right answer, such as what to return for disjoint ranges (`nil`, an empty range, or an exception). More fundamentally, it frames Range as a set-like collection, which invites `Range#union` next, and union of two ranges cannot be defined in general because the result may be discontiguous. I prefer to keep Range out of set algebra. Matz. ---------------------------------------- Feature #16757: Add intersection to Range https://bugs.ruby-lang.org/issues/16757#change-117998 * Author: stuyam (Stuart Yamartino) * Status: Closed ---------------------------------------- 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: ``` ruby (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: ``` ruby (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: 1. Performance: creating the ranges into arrays and doing array calculations can me slower based on the span of the range. 2. 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. 3. 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](https://bugs.ruby-lang.org/issues/16155) added for Array#& recently. I would propose Range#& and Range#intersection to have parity with Array and Set methods. -- https://bugs.ruby-lang.org/
participants (1)
-
matz (Yukihiro Matsumoto)