2009-03-30 15 views
16

私は2つの重複する範囲がある場合:2つの範囲が部分的にしか重なっているため(Ruby)範囲に別の範囲のサブセットが含まれているかどうかをどのように確認しますか?

false 

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

は、私が言う:

puts x.include? y 

出力されます。

しかし、2つの範囲の部分的な重なりがあるときに「真」にしたい場合、どうすればよいでしょうか?つまり、ある範囲に別の範囲のサブセットが含まれているかどうかを知る方法が必要です。 Rubyでこれを書くにはエレガントな方法があると思いますが、私が考えることができる唯一の解決策は冗長です。範囲は最初または第二の範囲の両端を含む場合

+2

出力i 'x.begin <= yとy <= x.end' --- _not_は部分的にしか重複しないため、' false'です。 – Kevin

答えて

7

は、大規模な範囲でこれを使用して注意してくださいが、これはそれを行うためのエレガントな方法です:

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

これは、O(N)のメモリと時間とMarkusQのO(1)の時間です。 – Barry

+0

番号の代わりに* time * ranges;を使用すると実際には使用できません –

59

効率的な方法は、制限

+0

なぜこれは配列に変換するより効率的ですか?配列への変換は多くのリソースを使用しますか? –

+1

さて、これは私の方法よりも優れています! – Angela

+1

配列に変換すると配列になり、値で塗りつぶしてから2番目の配列に対して同じ処理を行い、2つの配列で一致する項目を検索します。 x = 10000000..20000000とy = 30000000..40000000を設定して、2つの方法の時間を見てみましょう。 – MarkusQ

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

を比較することで、それらは重なり合います。

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

はこれと同じである:

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

[私のコメント](http://stackoverflow.com/questions/699448/ruby-how-do-you-check-whether-a-range-contains-a-subset-of-another-range#comment19657429_1337373)を参照してくださいそれが本当でない理由を見てください。 – jasonkarns

1

しかし、二つの範囲の間の部分的重複があるとき、私はそれが「真」になりたい場合は、 はどのように私はそれを書くのでしょうか?

あなたは配列の範囲を変換し、&オペレータ(組み合わせ)を使用することができます。これは、両方の配列にすべての要素がある新しい配列を返します。結果の配列が空でない場合、それは意味し、いくつかの重複要素があること:その後、私はちょうど

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

1つの範囲として行うだろう、

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

これは最も直感的な解決策のようです。 –

+1

@Chris - 「最も直感的」なのかもしれませんが、1)それはうんざりして非効率であり、2)整数範囲でしか動作しないので、私はそれを使用するようアドバイスしません。 – MarkusQ

1

あなたは重複をチェックしている場合だろう他方の端の少なくとも1つを含まなければならない。これは、MarkusQの限界比較と同じくらい効率的ではありませんが、受け入れられたconjuctionの回答よりも私には直感的です。

+1

これは、部分的に*重複する場合のみをカバーします。 'x = 3..6'と' y = 1..10'を指定すると、コードはfalseを返しますが、2つの範囲は実際に重なり合っています。 – jasonkarns

2

あなたは基本的にここで設定した交差点をやっているので、あなたはまた、setsに範囲を変換することができます。 3つ以上の範囲を扱う場合は、より簡単かもしれません。

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

素敵なテクニック。 – Anwar

-1

いくつかの有用な列挙方法:

# 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
この方法は、効率的な方法で複数の範囲の間のオーバーラップをテストするために使用することができる

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

RailsはRange#overlaps?

def overlaps?(other) 
    cover?(other.first) || other.cover?(first) 
end 
を有します
関連する問題