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

StackOverflow https://stackoverflow.com/questions/699448

  •  22-08-2019
  •  | 
  •  

Вопрос

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

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

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

puts x.include? y 

результатом является:

false 

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

Но если я хочу, чтобы это было "true" при частичном перекрытии двух диапазонов, как бы я это написал?Другими словами, мне нужен способ узнать, когда один диапазон содержит подмножество другого диапазона.Я предполагаю, что есть элегантный способ написать это на 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)

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

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

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)

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

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

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

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

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

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

# 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}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top