web-dev-qa-db-ja.com

Rubyの要素の順序を無視して2つの配列を比較する

2つの配列に同じデータが任意の順序で含まれているかどうかを確認する必要があります。架空のcompareメソッドを使用して、以下を実行します。

arr1 = [1,2,3,5,4]
arr2 = [3,4,2,1,5]
arr3 = [3,4,2,1,5,5]

arr1.compare(arr2) #true    
arr1.compare(arr3) #false

arr1.sort == arr2.sortを使用しましたが、動作しているようですが、これを行うより良い方法はありますか?

48
SimonMayer

比較する前に配列を並べ替えるのはO(n log n)です。さらに、Victorが指摘しているように、配列にソート不可能なオブジェクトが含まれていると、問題が発生します。ヒストグラムO(n)を比較する方が高速です。

Facetsには Enumerable#frequency がありますが、依存関係の追加を避けたい場合は、ご自身で簡単に実装できます。

require 'facets'
[1, 2, 1].frequency == [2, 1, 1].frequency 
#=> true
32
tokland

最も簡単な方法は、交差点を使用することです。

@array1 = [1,2,3,4,5]
@array2 = [2,3,4,5,1]

だから声明

@array2 & @array1 == @array2

trueになります。これは、array1array2が含まれているか、反対の(異なる)かを確認する場合に最適なソリューションです。また、配列をいじったり、項目の順序を変更したりすることもありません。また、サイズを同一にしたい場合は、両方の配列の長さを比較することもできます。

また、それを行うための最速の方法です(間違っている場合は修正してください)

36
MMM

どの配列にも繰り返しがないことがわかっている場合(つまり、すべての要素が一意であるか気にしないか)、セットの使用は簡単で読みやすいです:

Set.new(array1) == Set.new(array2)
18
Gunchars

実際にこれを実装できます#compareメソッド monkey patching このようなArrayクラス:

class Array
  def compare(other)
    sort == other.sort
  end
end

モンキーパッチングがグッドプラクティスと見なされることはめったにないので注意してください。

おそらくこれを行うためのより良い方法がありますが、それが思い浮かびました。それが役に立てば幸い!

6

arrayクラスを開き、このようなメソッドを定義できます。

class Array
  def compare(comparate)
    to_set == comparate.to_set
  end
end

arr1.compare(arr2)
irb => true

または単に使用する

arr1.to_set == arr2.to_set
irb => true
3
Datt

私が見つけた最もエレガントな方法:

arr1 = [1,2,3,5,4]
arr2 = [3,4,2,1,5]
arr3 = [3,4,2,1,5,5]


(arr1 - arr2).empty? 
=> true

(arr3 - arr2).empty?
=> false
3
Lukasz Muzyka

以下は、ソートできない配列で動作するバージョンです

class Array
  def unordered_hash
    unless @_compare_o && @_compare_o == hash
      p = Hash.new(0)
      each{ |v| p[v] += 1 }
      @_compare_p = p.hash
      @_compare_o = hash
    end
    @_compare_p
  end
  def compare(b)
    unordered_hash == b.unordered_hash
  end
end

a = [ 1, 2, 3, 2, nil ]
b = [ nil, 2, 1, 3, 2 ]
puts a.compare(b)
0