Ruby: intersection between two ranges
require 'date'class Range def intersection(other) return nil if (self.max < other.begin or other.max < self.begin) [self.begin, other.begin].max..[self.max, other.max].min end alias_method :&, :intersectionendp (Date.new(2011,1,1)..Date.new(2011,1,15)) & (Date.new(2011,1,10)..Date.new(2011,2,15))#<Date: 2011-01-10 ((2455572j,0s,0n),+0s,2299161j)>..#<Date: 2011-01-15 ((2455577j,0s,0n),+0s,2299161j)>
You can try this to get a range representing intersection
range1 = Date.new(2011,12,1)..Date.new(2011,12,10)range2 = Date.new(2011,12,4)..Date.new(2011,12,12)inters = range1.to_a & range2.to_aintersected_range = inters.min..inters.max
Converting your example:
class Range def intersection(other) raise ArgumentError, 'value must be a Range' unless other.kind_of?(Range) inters = self.to_a & other.to_a inters.empty? ? nil : inters.min..inters.max end alias_method :&, :intersection end
I baked this solution for ascending ranges, also taking care of the exclude end situations:
intersect_ranges = ->(r1, r2) do new_end = [r1.end, r2.end].min new_begin = [r1.begin, r2.begin].max exclude_end = (r2.exclude_end? && new_end == r2.end) || (r1.exclude_end? && new_end == r1.end) valid = (new_begin <= new_end && !exclude_end) valid ||= (new_begin < new_end && exclude_end)) valid ? Range.new(new_begin, new_end, exclude_end) : nilend
I'm also a bit worried by you guys adding it to the Range class itself, since the behavior of intersecting ranges is not uniformly defined. (How about intersecting 1...4 and 4...1? Why nil when there is no intersection; we could also say this is an empty range: 1...1 )