检查ruby中两个范围是否重叠

时间:2016-10-08 15:41:30

标签: ruby

我知道我能做到:

        return render(request, ('core/add_regent.html', context_dict), {'form': form})

但是当我尝试对另一个范围做同样的事情时,它总是返回false:

(1..30).cover?(2)
=> true

所以我的问题是 - 有没有优雅的方法来比较红宝石中的两个范围?在我的情况下,我想检查两个DateTime范围是否重叠。提前谢谢。

6 个答案:

答案 0 :(得分:7)

在以下情况下,给定范围A的两个范围重叠:

  1. 范围B在范围A
  2. 内开始
  3. 范围B在范围A或
  4. 范围内结束
  5. 范围B在范围A之前开始,在范围A之后结束
  6. 示例:

    Range A    |-----|
                 |-----|  Case 1
             |-----|      Case 2
                 |-|      Case 1 + 2
             |---------|  Case 3
    

    仔细观察规则:当范围B在范围A结束之前开始范围B时,两个范围重叠,而范围B在范围A开始之后结束。

    def ranges_overlap?(range_a, range_b)
      range_b.begin <= range_a.end && range_a.begin <= range_b.end 
    end 
    

    更新: Range#cover?方法现在接受范围类型参数。当您使用Ruby版本>= 2.6时,以下内容开箱即用:

    (1..30).cover?(2..3)
    #=> true
    

答案 1 :(得分:5)

def overlap?(r1,r2)
  !(r1.first > r2.last || r1.last < r2.first)
end

overlap? 1..5, 4..10 #=> true
overlap? 1..5, 6..10 #=> false
overlap? 1..10, 4..8 #=> true
overlap? 1..4, 4..8  #=> true

操作线相当于:

r1.first <= r2.last && r1.last >= r2.first

我通常会尽量避免否定,但在这种情况下,我认为用它读得更好。

另一种方式:

def overlap?(r1,r2)
  !(([r1.first, r2.first].min..[r1.last, r2.last].max).size >= r1.size + r2.size)
end

overlap? 1..5, 4..10 #=> true
overlap? 1..5, 6..10 #=> false
overlap? 1..10, 4..8 #=> true
overlap? 1..4, 4..8  #=> true

操作线相当于:

([r1.first, r2.first].min..[r1.last, r2.last].max).size < r1.size + r2.size

同样,我更喜欢带有否定的那个。

答案 2 :(得分:3)

虽然转换可能会浪费,但语义上比较集合似乎最有意义:

Set.new(1..30).superset?(Set.new(2..3))
#=> true
Set.new(1..30).superset?(Set.new(0..3))
#=> false

如果您不想这样做,可以执行以下操作(r1r2为范围):

r1.cover?(r2.min) && r1.cover?(r2.max)

答案 3 :(得分:0)

您可以使用检查重叠 range1.first < range2.last && range2.first < range1.last
您可以将其添加为范围的实例方法或作为数据中某处的辅助方法。 来源:https://stackoverflow.com/a/325964/4091324

答案 4 :(得分:0)

在轨道上,您可以使用(1..3).overlaps?(2..4) # true

https://apidock.com/rails/Range/overlaps

答案 5 :(得分:0)

如果你想要 Rails 实现,你可以使用

class Range
  def overlaps?(other)
    cover?(other.first) || other.cover?(first)
  end
end
(1..5).overlaps?(4..6) # => true
(1..5).overlaps?(7..9) # => false