(Ruby)如何检查范围是否包含另一个范围的子集?

如果我有两个重叠的范围:

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

当我说:

 puts x.include? y 

输出是:

 false 

因为这两个范围只是部分重叠。

但是如果我希望当两个范围之间存在部分重叠时它是“真实的”,我该怎么写呢? 换句话说,我需要一种方法来知道一个范围何时包含另一个范围的子集。 我假设有一种优雅的方式在Ruby中编写它,但我能想到的唯一解决方案是冗长的。

使用大范围时要小心,但这是一种优雅的方法:

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

有效的方法是比较限制

 (x.first <= y.last) and (y.first <= x.last) 

您也可以将范围转换为集合 ,因为您基本上在这里进行集合交集。 如果您处理两个以上的范围,可能会更容易。

 x = (1..10).to_set y = (5..15).to_set !(x & y).empty? #returns true (true == overlap, false == no overlap) 

此方法可用于以有效的方式测试多个范围之间的重叠:

 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]] 

如果范围包括第二个范围的开头或结尾,则它们重叠。

 (x === y.first) or (x === y.last) 

与此相同:

 x.include?(y.first) or x.include?(y.last) 

但是如果我希望当两个范围之间存在部分重叠时它是“真实的”,我该怎么写呢?

您可以将范围转换为数组,并使用&运算符( 连接) 。 这将返回一个新数组,其中包含两个数组中的所有元素。 如果结果数组不为空,则表示存在一些重叠元素:

 def overlap?(range_1, range_2) !(range_1.to_a & range_2.to_a).empty? end 

如果你正在检查重叠,那我就是这么做的

 (x.include? y.first) or (x.include? y.last) 

因为一个范围必须至少包括另一个范围的一端。 这比我接受的结合答案更直观,但不如MarkusQ的限制比较效率高。

Rails有Range#重叠?

 def overlaps?(other) cover?(other.first) || other.cover?(first) end 

一些有用的可枚举方法:

 # x is a 'subset' of y x.all?{|n| y.include? n} # x and y overlap x.any?{|n| y.include? n} # x and y do not overlap x.none?{|n| y.include? n} # x and y overlap one time x.one?{|n| y.include? n}