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

时间:2021-09-14 07:28:55

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.

但如果我想让它为“真”当两个区间有部分重叠时,我怎么写呢?换句话说,我需要一种方法来知道一个范围何时包含另一个范围的子集。我认为有一种优雅的方法可以用Ruby编写它,但是我能想到的唯一解决方案是冗长的。

9 个解决方案

#1


7  

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

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

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

#2


59  

The efficient way is to compare the limits

有效的方法是比较极限

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

#3


2  

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)

#4


2  

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

#5


1  

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)

#6


1  

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

#7


1  

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.

因为一个范围必须包含另一个范围的至少一端。对我来说,这比公认的魔法答案更直观,尽管没有MarkusQ的极限比较那么有效。

#8


0  

Rails has Range#overlaps?

Rails #重叠范围吗?

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

#9


-1  

Some helpful enumerable methods:

一些有用的可枚举的方法:

# 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}

#1


7  

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

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

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

#2


59  

The efficient way is to compare the limits

有效的方法是比较极限

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

#3


2  

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)

#4


2  

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

#5


1  

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)

#6


1  

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

#7


1  

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.

因为一个范围必须包含另一个范围的至少一端。对我来说,这比公认的魔法答案更直观,尽管没有MarkusQ的极限比较那么有效。

#8


0  

Rails has Range#overlaps?

Rails #重叠范围吗?

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

#9


-1  

Some helpful enumerable methods:

一些有用的可枚举的方法:

# 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}