If I have two ranges that overlap:
x = 1..10
y = 5..15
When I say:
puts x.include? y
the output is:
If a range includes either the beginning or the end of a second range, then they overlap.
(x === y.first) or (x === y.last)
is the same as this:
x.include?(y.first) or x.include?(y.last)
This method can be used to test overlap between multiple ranges in an efficient way:
def range_overlap?(ranges)
sorted_ranges = ranges.sort
sorted_ranges.each_cons(2).each do |r1, r2|
return true if r2.first <= r1.last
end
return false
end
def test(r)
puts r.inspect, range_overlap?(r)
puts '================'
r = r.reverse
puts r.inspect, range_overlap?(r)
puts '================'
end
test [[1,9], [10, 33]]
test [[1,10], [5, 8]]
test [[1,10], [10, 33]]
If you're using Ruby 2.6, you can use Range#cover? with another Range
.
(1..5).cover?(2..3) #=> true
(1..5).cover?(0..6) #=> false
(1..5).cover?(1...6) #=> true
You could also convert the ranges to sets, since you're basically doing set intersection here. Might be easier if you are dealing with more than two ranges.
x = (1..10).to_set
y = (5..15).to_set
!(x & y).empty? #returns true (true == overlap, false == no overlap)
The efficient way is to compare the limits
(x.first <= y.last) and (y.first <= x.last)
If you're checking for overlap, then I'd just do
(x.include? y.first) or (x.include? y.last)
as one range will have to include at least one of the ends of the other. This is more intuitive to me than the accepted conjuction answer, though not quite as efficient as MarkusQ's limit comparison.