web-dev-qa-db-ja.com

1つの配列に別の配列のすべての要素が含まれているかどうかを確認する方法

与えられた:

a1 = [5, 1, 6, 14, 2, 8]

以下のすべての要素が含まれているかどうかを確認したいと思います。

a2 = [2, 6, 15]

この場合、結果はfalseです。

そのような配列の包含を識別する組み込みのRuby/Railsメソッドはありますか?

これを実装する1つの方法は次のとおりです。

a2.index{ |x| !a1.include?(x) }.nil?

より良い、より読みやすい方法はありますか?

165
Misha Moroshko
a = [5, 1, 6, 14, 2, 8]
b = [2, 6, 15]

a - b
=> [5, 1, 14, 8]

b - a
=> [15]

(b - a).empty?
=> false
289
Geo

おそらくこれは読みやすいです:

a2.all? { |e| a1.include?(e) }

配列交差を使用することもできます:

(a1 & a2).size == a1.size

ここではsizeが速度のためだけに使用されていることに注意してください。

(a1 & a2) == a1

しかし、最初の方が読みやすいと思います。これら3つは、プレーンRuby(Railsではありません)です。

71
Pablo Fernandez

これを行うことで達成できます

(a2 & a1) == a2

これにより、両方の配列の共通部分が作成され、a2にあるa1からすべての要素が返されます。結果がa2と同じ場合、すべての要素がa1に含まれていることを確認できます。

このアプローチは、最初にa2のすべての要素が互いに異なる場合にのみ機能します。ダブルがある場合、このアプローチは失敗します。 Temposのものは今でも動作するので、私は心から彼のアプローチをお勧めします(また、おそらくより高速です)。

53
Holger Just

重複する要素がないか、それらを気にしない場合は、 Set クラスを使用できます。

a1 = Set.new [5, 1, 6, 14, 2, 8]
a2 = Set.new [2, 6, 15]
a1.subset?(a2)
=> false

これが使用する舞台裏

all? { |o| set.include?(o) }
10
Confusion

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
1
Zack Xu

いずれかの配列に要素が重複している場合、(a1-a2)または(a1&a2)に基づくほとんどの回答は機能しません。私はここに到着し、Wordのすべての文字(配列に分割)が文字のセット(スクラブルなど)の一部であるかどうかを確認する方法を探しました。これらの答えはどれも機能しませんでしたが、これは機能します。

def contains_all?(a1, a2)
  try = a1.chars.all? do |letter|
    a1.count(letter) <= a2.count(letter)
  end
  return try
end
0
Charles Breton

配列の大きさに応じて、効率的なアルゴリズム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)です。他のアルゴリズムは、ソートされていない配列を使用して(漸近的に)高速化することはできません。

0
ayckoster