Подтвердить что ты не робот

(Ruby) Как проверить, содержит ли диапазон подмножество другого диапазона?

Если у меня есть два диапазона, которые перекрываются:

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

Когда я говорю:

puts x.include? y 

вывод:

false 

потому что два диапазона частично перекрываются.

Но если я хочу, чтобы он был "истинным", когда есть частичное перекрытие между двумя диапазонами, как бы я это написал? Другими словами, мне нужен способ узнать, когда один диапазон содержит подмножество другого диапазона. Я предполагаю там элегантный способ написать это в Ruby, но единственные решения, о которых я могу думать, являются подробными.

4b9b3361

Ответ 1

Будьте осторожны, используя это с большими диапазонами, но это элегантный способ сделать это:

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

Ответ 2

Эффективным способом является сравнение пределов

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

Ответ 3

Вы также можете преобразовать диапазоны в sets, так как вы в основном выполняете заданное пересечение здесь. Может быть проще, если вы имеете дело с более чем двумя диапазонами.

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

Ответ 4

Этот метод может быть использован для эффективного тестирования перекрытия между несколькими диапазонами:

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

Если диапазон включает либо начало, либо конец второго диапазона, то они перекрываются.

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

совпадает с этим:

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

Ответ 6

Но если я хочу, чтобы он был "истинным", когда есть частичное перекрытие между двумя диапазонами, как бы я это написал?

Вы можете преобразовать диапазоны в массив и использовать оператор & (соединение). Это возвращает новый массив со всеми элементами, происходящими в обоих массивах. Если результирующий массив не пуст, это означает, что есть некоторые перекрывающиеся элементы:

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

Ответ 7

Если вы проверяете перекрытие, тогда я просто сделаю

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

поскольку один диапазон должен включать по крайней мере один из концов другого. Это более интуитивно для меня, чем принятый ответ на конкатентность, хотя и не столь эффективный, как сравнение ограничений MarkusQ.

Ответ 9

Если вы используете Ruby 2.6, вы можете использовать Range#cover? с другим Range.

(1..5).cover?(2..3)     #=> true
(1..5).cover?(0..6)     #=> false
(1..5).cover?(1...6)    #=> true

Ответ 10

Некоторые полезные перечисляемые методы:

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