2个范围集之间的交集

时间:2016-03-02 17:01:47

标签: ruby

我如何在ruby中进行范围拦截?

像这样:

[-4, 3] intersection [-2, 5] = [-2, 3]
[10, 20] intersection [5, 10] = [10]
[-10, -5] intersection [-8, -3] = [-8,-5]
[-5, -3] intersection [2, 20] = nil

3 个答案:

答案 0 :(得分:2)

def foo((a, b), (c, d))
  min, max = [a, c].max, [b, d].min
  case min <=> max
  when -1 then [min, max]
  when 0 then [min]
  when 1 then nil
  end
end

foo([-4, 3], [-2, 5]) # => [-2, 3]
foo([10, 20], [5, 10]) # => [10]
foo([-10, -5], [-8, -3]) # => [-8, -5]
foo([-5, -3], [2, 20]) # => nil

答案 1 :(得分:2)

class Range
  def range_overlap(other)
    [self.min, other.min].max..[self.max, other.max].min
  end
end

(-4..3  ).range_overlap -2..5  #=> -2..3
(10..20 ).range_overlap 5..10  #=> 10..10
(-10..-5).range_overlap -8..-3 #=> -8..-5
(-5..-3 ).range_overlap -2..20 #=> -2..-3 
(1..4   ).range_overlap 2..3   #=> 2..3 
r.first > r.last一样,

r = -2..-3表示没有重叠。如果您希望在这种情况下退回nil,请使用

r = ([self.min, other.min].max)..([self.max, other.max].min)
r.last >= r.first ? r : nil

我还返回了[10,10]而不是10(当然不是[10]),因为我认为这会让您的后续代码更容易编写。 (它类似于返回[[1,2], [3], [4,5]]而不是[[1,2], 3, [4,5]]的方法。)

我认为最好总是返回Range个对象。这允许后续代码被写入,例如:

r = range_overlap(other)
case r.first <=> r.last
  when 1 # r.first > r.last
     <put out the trash>
  when 0 # r.first == r.last
     <let the cat out>
  else   # r.first < r.last
     <go to a movie>
end

答案 2 :(得分:0)

f = [-4, 3]
s = [-2, 5]
inter = [[f[0],s[0]].max, [f[1],s[2]].min].uniq
inter = nil if inter[1] && inter[1] < inter[0]