与えられた:
a1 = [5, 1, 6, 14, 2, 8]
次のすべての要素が含まれているかどうかを確認したいと思います。
a2 = [2, 6, 15]
この場合の結果はfalse
です。
そのような配列の包含を識別するための組み込みのRuby / Railsメソッドはありますか?
これを実装する1つの方法は次のとおりです。
a2.index{ |x| !a1.include?(x) }.nil?
より良い、より読みやすい方法はありますか?
与えられた:
a1 = [5, 1, 6, 14, 2, 8]
次のすべての要素が含まれているかどうかを確認したいと思います。
a2 = [2, 6, 15]
この場合の結果はfalse
です。
そのような配列の包含を識別するための組み込みのRuby / Railsメソッドはありますか?
これを実装する1つの方法は次のとおりです。
a2.index{ |x| !a1.include?(x) }.nil?
より良い、より読みやすい方法はありますか?
回答:
a = [5, 1, 6, 14, 2, 8]
b = [2, 6, 15]
a - b
=> [5, 1, 14, 8]
b - a
=> [15]
(b - a).empty?
=> false
(a2-a1).empty?
(a2.uniq - a1.uniq).empty?
おそらくこれは読みやすいでしょう:
a2.all? { |e| a1.include?(e) }
配列の交差を使用することもできます。
(a1 & a2).size == a1.size
ここでsize
は速度のためだけに使用されていることに注意してください。次のこともできます(遅い):
(a1 & a2) == a1
しかし、私は最初の方が読みやすいと思います。これら3つはプレーンルビーです(レールではありません)。
これは、
(a2 & a1) == a2
これにより、両方の配列の共通部分が作成され、a2
そこにもあるすべての要素が返されa1
ます。結果がと同じ場合は、a2
すべての要素がに含まれていることを確認できますa1
。
このアプローチが機能するa2
のは、そもそもすべての要素が互いに異なる場合のみです。ダブルがある場合、このアプローチは失敗します。テンポスのものはそれでもまだ機能するので、私は心から彼のアプローチをお勧めします(おそらくもっと速いです)。
length
方法を使用するとパフォーマンスが大幅に向上します
Arrayクラスをサルパッチすることができます:
class Array
def contains_all?(ary)
ary.uniq.all? { |x| count(x) >= ary.count(x) }
end
end
テスト
irb(main):131:0> %w[a b c c].contains_all? %w[a b c]
=> true
irb(main):132:0> %w[a b c c].contains_all? %w[a b c c]
=> true
irb(main):133:0> %w[a b c c].contains_all? %w[a b c c c]
=> false
irb(main):134:0> %w[a b c c].contains_all? %w[a]
=> true
irb(main):135:0> %w[a b c c].contains_all? %w[x]
=> false
irb(main):136:0> %w[a b c c].contains_all? %w[]
=> true
irb(main):137:0> %w[a b c d].contains_all? %w[d c h]
=> false
irb(main):138:0> %w[a b c d].contains_all? %w[d b c]
=> true
もちろん、メソッドは標準の単独メソッドとして書くことができます、例えば
def contains_all?(a,b)
b.uniq.all? { |x| a.count(x) >= b.count(x) }
end
そしてあなたはそれを次のように呼び出すことができます
contains_all?(%w[a b c c], %w[c c c])
実際、プロファイリング後の次のバージョンははるかに高速で、コードは短くなっています。
def contains_all?(a,b)
b.all? { |x| a.count(x) >= b.count(x) }
end
配列の大きさに応じて、効率的なアルゴリズムO(n log n)を検討できます
def equal_a(a1, a2)
a1sorted = a1.sort
a2sorted = a2.sort
return false if a1.length != a2.length
0.upto(a1.length - 1) do
|i| return false if a1sorted[i] != a2sorted[i]
end
end
ソートにはO(n log n)がかかり、各ペアのチェックにはO(n)がかかります。したがって、このアルゴリズムはO(n log n)です。他のアルゴリズムは、ソートされていない配列を使用すると(漸近的に)より速くなることはできません。
(a1-a2)または(a1&a2)に基づくほとんどの回答は、いずれかの配列に重複する要素がある場合は機能しません。単語のすべての文字(配列に分割)が一連の文字(たとえばスクラブル)の一部であるかどうかを確認する方法を探して、ここに到着しました。これらの答えはどれもうまくいきませんでしたが、これはうまくいきました:
def contains_all?(a1, a2)
try = a1.chars.all? do |letter|
a1.count(letter) <= a2.count(letter)
end
return try
end