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

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

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

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

puts x.include? y 

вывод:

false 

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

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

Ответы [ 10 ]

61 голосов
/ 31 марта 2009

Эффективный способ - сравнить пределы

(x.first <= y.last) and (y.first <= x.last)
8 голосов
/ 12 ноября 2009

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

(x.to_a & y.to_a).empty?
2 голосов
/ 21 мая 2012

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

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]]
2 голосов
/ 29 мая 2011

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

x = (1..10).to_set
y = (5..15).to_set
!(x & y).empty? #returns true (true == overlap, false == no overlap)
1 голос
/ 27 августа 2009

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

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

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

1 голос
/ 31 марта 2009

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

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

def overlap?(range_1, range_2)
  !(range_1.to_a & range_2.to_a).empty?
end
1 голос
/ 31 марта 2009

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

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

такой же, как этот:

x.include?(y.first) or x.include?(y.last)
0 голосов
/ 24 мая 2019

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

(1..5).cover?(2..3)     #=> true
(1..5).cover?(0..6)     #=> false
(1..5).cover?(1...6)    #=> true
0 голосов
/ 26 июля 2016

Рельсы имеют Диапазон # перекрытий?

def overlaps?(other)
  cover?(other.first) || other.cover?(first)
end
0 голосов
/ 30 января 2012

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

# 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}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...