web-dev-qa-db-ja.com

2つの配列の内容が同じかどうか(任意の順序で)を確認します

私はRuby 1.8.6 with Rails 1.2.3を使用しており、2つの配列が同じ要素を持っているかどうかにかかわらず、同じ順序になっています。配列の1つに重複が含まれないことが保証されています(他の配列は、その場合、答えはノーです)。

私の最初の考えは

require 'set'
a.to_set == b.to_set

しかし、もっと効率的または慣用的な方法があるのだろうかと思っていました。

77
Taymon

これは設定するために変換を必要としません:

a.sort == b.sort
121
Mori

2つの配列AとBの場合:AとBは、次の場合に同じ内容を持ちます:_(A-B).blank? and (B-A).blank?_

または、次のことを確認できます:_((A-B) + (B-A)).blank?_

また、@ cort3zで示唆されているように、このソリューションals0はポリモーフィック配列、つまり

_ A = [1 , "string", [1,2,3]]
 B = [[1,2,3] , "string", 1]
 (A-B).blank? and (B-A).blank? => true
 # while A.uniq.sort == B.uniq.sort will throw error `ArgumentError: comparison of Fixnum with String failed` 
_

::::::::::: EDIT :::::::::::::

コメントで示唆されているように、上記の解決策は重複に対して失敗しますが、質問によると、質問者は重複に興味がないので、チェックする前に配列をセットに変換し、重複をマスクし、彼がチェックする前に.uniq演算子を使用しており、それも重複をマスクしています。ただし、重複が興味のある場合は、カウントのチェックを追加するだけで同じ問題が修正されます(質問により、重複を含めることができるのは1つの配列のみです)。最終的な解決策は次のようになります:A.size == B.size and ((A-B) + (B-A)).blank?

38
Sahil Dhankhar

スピード比較

require 'benchmark/ips'
require 'set'

a = [1, 2, 3, 4, 5, 6]
b = [1, 2, 3, 4, 5, 6]

Benchmark.ips do |x|
  x.report('sort')   { a.sort == b.sort }  
  x.report('sort!')  { a.sort! == b.sort! }  
  x.report('to_set') { a.to_set == b.to_set }  
  x.report('minus')  { ((a - b) + (b - a)).empty? }  
end  

Warming up --------------------------------------
            sort    88.338k i/100ms
           sort!   118.207k i/100ms
          to_set    19.339k i/100ms
           minus    67.971k i/100ms
Calculating -------------------------------------
            sort      1.062M (± 0.9%) i/s -      5.389M in   5.075109s
           sort!      1.542M (± 1.2%) i/s -      7.802M in   5.061364s
          to_set    200.302k (± 2.1%) i/s -      1.006M in   5.022793s
           minus    783.106k (± 1.5%) i/s -      3.942M in   5.035311s
19
Morozov

aおよびbの要素が Comparable の場合、

a.sort == b.sort

@steenslagのコメントに基づく@moriの回答の修正

14
Jared Beck

[:a, :b] != [:a, :a, :b]to_setは機能しません。代わりに頻度を使用できます:

class Array
  def frequency
    p = Hash.new(0)
    each{ |v| p[v] += 1 }
    p
  end
end

[:a, :b].frequency == [:a, :a, :b].frequency #=> false
[:a, :b].frequency == [:b, :a].frequency #=> true
7
Victor Moroz

配列の長さが同じで、どちらの配列にも重複が含まれていないことがわかっている場合、これも機能します。

_( array1 & array2 ) == array1
_

説明:この場合の_&_演算子は、a2で見つからない項目を除くa1のコピーを返します。これは、両方の配列が同じコンテンツを重複なしで持っている場合、元のa1と同じです。

Analyis:順序は変わらないので、これは一貫してO(n*n)のように二重反復として実装されていると推測します。特に、大きい配列では_a1.sort == a2.sort_よりも悪い最悪の場合O(n*logn)で実行します。

6
Nat

Ruby 2.6 +

Rubyで difference が2.6に導入されました。

これにより、次のように非常に高速で読みやすいソリューションが得られます。

a = [1, 2, 3, 4, 5, 6]
b = [1, 2, 3, 4, 5, 6]

a.difference(b).any?
# => false
a.difference(b.reverse).any?
# => false

a = [1, 2, 3, 4, 5, 6]
b = [1, 2, 3]
a.difference(b).any?
# => true

ベンチマークの実行:

a = Array.new(1000) { Rand(100) }
b = Array.new(1000) { Rand(100) }

Benchmark.ips do |x|
  x.report('sort')   { a.sort == b.sort }  
  x.report('sort!')  { a.sort! == b.sort! }  
  x.report('to_set') { a.to_set == b.to_set }  
  x.report('minus')  { ((a - b) + (b - a)).empty? }  
  x.report('difference') { a.difference(b).any? }
end

      sort     13.908k (± 2.6%) i/s -     69.513k in   5.001443s
     sort!     14.656k (± 3.0%) i/s -     73.736k in   5.035744s
    to_set     5.125k  (± 2.9%) i/s -     26.023k in   5.082083s
     minus     16.398k (± 2.2%) i/s -     83.181k in   5.074938s
difference     27.839k (± 5.2%) i/s -    141.048k in   5.080706s

それが誰かを助けることを願っています!

4
SRack

1つのアプローチは、重複なしで配列を反復処理することです

# assume array a has no duplicates and you want to compare to b
!a.map { |n| b.include?(n) }.include?(false)

これは、真の配列を返します。 falseが表示される場合、外側のinclude?はtrueを返します。したがって、全体を反転させて、一致するかどうかを判断する必要があります。

1
Ron

結合&sizeも高速かもしれません。

require 'benchmark/ips'
require 'set'

Benchmark.ips do |x|
  x.report('sort')   { a.sort == b.sort }  
  x.report('sort!')  { a.sort! == b.sort! }  
  x.report('to_set') { a.to_set == b.to_set }  
  x.report('minus')  { ((a - b) + (b - a)).empty? }
  x.report('&.size') { a.size == b.size && (a & b).size == a.size }  
end  

Calculating -------------------------------------
                sort    896.094k (±11.4%) i/s -      4.458M in   5.056163s
               sort!      1.237M (± 4.5%) i/s -      6.261M in   5.071796s
              to_set    224.564k (± 6.3%) i/s -      1.132M in   5.064753s
               minus      2.230M (± 7.0%) i/s -     11.171M in   5.038655s
              &.size      2.829M (± 5.4%) i/s -     14.125M in   5.010414s
1
Todoroki