tags:

views:

853

answers:

5

If I have two ranges that overlap:

x = 1..10
y = 5..15

When I say:

puts x.include? y

the output is:

false

because the two ranges only overlap partially.

But if I want it to be "true" when there is partial overlap between two ranges, how would I write that? In other words I need a way to know when one range contains a subset of another range. I assume there's an elegant way to write this in Ruby but the only solutions I can think of are verbose.

+20  A: 

The efficient way is to compare the limits

(x.first <= y.last) and (y.first <= x.last)
MarkusQ
Why is this more efficient than converting to an array? Does converting to an array use a lot of resources?
Okay, this is way better than mine!
Angela
Converting it to an array makes an array and fills it with values, then does the same for the second array, then searches the two arrays for matching items. set x = 10000000..20000000 and y = 30000000..40000000 and time the two methods to see what I mean.
MarkusQ
+1  A: 

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)
Evgeny
+1  A: 

But if I want it to be "true" when there is partial overlap between two ranges, how would I write that?

You can convert the ranges to an array, and use the & operator (conjunction). This returns a new array with all the elements occuring in both arrays. If the resulting array is not empty, that means, that there are some overlapping elements:

def overlap?(range_1, range_2)
  !(range_1.to_a & range_2.to_a).empty?
end
Soleone
This seems like the most intuitive solution.
@Chris -- It may be "the most intuitive" but 1) it's ridiculously inefficient and 2) it only works on integer ranges, so I wouldn't advise using it.
MarkusQ
+1  A: 

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.

Xiong Chiamiov
+1  A: 

Be careful using this with large ranges but this is an elegant way to do it:

(x.to_a & y.to_a).empty?
ski