(Ruby) Comment vérifier si une gamme contient un sous-ensemble d'une autre plage?

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

  •  22-08-2019
  •  | 
  •  

Question

Si j'ai deux gammes qui se chevauchent:

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

Quand je dis:

puts x.include? y 

la sortie est la suivante:

false 

parce que les deux plages se chevauchent seulement partiellement.

Mais si je veux que ce soit « vrai » quand il y a chevauchement partiel entre les deux gammes, comment pourrais-je écrire cela? En d'autres termes je besoin d'un moyen de savoir quand une gamme contient un sous-ensemble d'une autre plage. Je suppose qu'il ya une façon élégante d'écrire ceci dans Ruby, mais les seules solutions que je peux penser sont verbeux.

Était-ce utile?

La solution

Soyez prudent en utilisant ce avec de grandes plages, mais cela est une façon élégante de le faire:

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

Autres conseils

La façon efficace est de comparer les limites

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

Vous pouvez également convertir les plages jeux , puisque vous faites essentiellement intersection ensemble ici. Peut-être plus facile si vous faites affaire avec plus de deux gammes.

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

Cette méthode peut être utilisée pour tester le chevauchement entre plusieurs plages de manière efficace:

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

Si une gamme comprend soit le début ou la fin d'une deuxième gamme, alors qu'elles se chevauchent.

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

est la même que celle-ci:

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

Mais si je veux que ce soit « vrai » quand il y a chevauchement partiel entre les deux gammes,   comment pourrais-je écrire cela?

Vous pouvez convertir les gammes à un tableau, et utiliser l'opérateur & ( conjonction) . Cela renvoie un nouveau tableau avec tous les éléments qui se produisent dans les deux tableaux. Si le tableau résultant est pas vide, cela signifie, qu'il ya des éléments qui se chevauchent:

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

Si vous vérifiez de chevauchement, alors que je venais de faire

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

comme une gamme devra inclure au moins l'une des extrémités de l'autre. Ceci est plus intuitive pour moi que la réponse acceptée conjuction, mais pas tout à fait aussi efficace que la comparaison limite de MarkusQ.

Rails a Range # chevauche

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

Si vous utilisez Ruby 2.6, vous pouvez utiliser Range#cover? avec un autre Range.

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

Quelques méthodes utiles dénombrables:

# 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}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top