2つの配列の内容が同じかどうかを確認します(順不同)。


90

Ruby 1.8.6とRails 1.2.3を使用していますが、2つの配列が同じ順序であるかどうかに関係なく、2つの配列に同じ要素があるかどうかを確認する必要があります。配列の1つは重複を含まないことが保証されています(もう1つは可能性があり、その場合の答えはノーです)。

私の最初の考えは

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

しかし、私はそれを行うためのより効率的なまたは慣用的な方法があるかどうか疑問に思っていました。



array.should =〜another_arrayチェックしてみstackoverflow.com/questions/2978922/...
アテナ

1)配列の要素が必ずソート可能かどうかを述べることで、多くの混乱を回避できたはずです。2)「2つの配列に同じ要素があるかどうか」などの意味を明確にするための簡単な例を提供します(たとえば、同じ要素[1,2][2,1,1]持っていますか?)
Cary Swoveland

Ruby 2.6が導入されdifference、非常に高速で読みやすいソリューションを提供します。詳細はこちら。
SRack

回答:


140

これを設定するための変換は必要ありません。

a.sort == b.sort

変換なし?何が.uniq.sort、その後?その上uniqto_set内部的に追加されたものに似ています.to_a.sort
Victor Moroz '06 / 06/18

uniqs なしではあるが、私が最終的に使用したものに最も近いため、これを受け入れる。実際、私は配列の1つをで作成することRange#to_aになったのでsort、もう1つだけで済みました。
Taymon

11
配列に単純にソートできない要素が含まれている場合(ハッシュの配列など)、これは機能しません。sahil dhankharのソリューションは、より一般的なソリューションのようです。
ブラッド2013

40

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?


どちらかの配列に重複が含まれている場合、これは失敗します。例えば、もしA=[1]およびB=[1,1]、両方(A-B)(B-A)空白を返します。Array Documentationを参照してください。
jtpereyda 2013

@dafrazzmanはあなたに完全に同意します。私はあなたのフィードバックを組み込むために私の回答を変更しました。しかし、質問(または承認された回答)をよく見ている場合、質問者は以下を使用しています:a.to_set == b.to_set 承認された回答が使用してa.uniq.sort == b.uniq.sortおり、どちらも((A-B) + (B-A)).blank?A = [1] とまったく同じ結果が得られますそしてB = [1,1]は同意しますか?彼は元の解決策の改善を求めていたので、私の元の解決策はまだ機能しています:)。同意する?
Sahil Dhankhar、2013

1
このソリューションは複数のタイプのオブジェクトを処理するため、非常に優れています。とがあるA = [123, "test", [], some_object, nil]とするとB = A#because I am lazyA.uniq.sortエラーがスローされます(文字列と配列の比較に失敗しました)。
Automatico、

それは配列サイズに依存しているので、これはO(n)でしょうか?(リニア)
user3007294 2016

1
配列のサイズは同じであるが、繰り返される要素が同じでない場合は機能しません。たとえばA = [1, 1, 2]B = [1, 2, 2]
Boudi、

23

速度比較

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

要素の順序は、sort速度に影響しません
モロゾフ

驚いた... セットの比較は、セットのルックアップO(n)時間の複雑さのため、他のすべてのパフォーマンスを上回ると期待していました。そのため、適切に実装された並べ替えにはO(n logn)が必要になります。セットへのキャストと値の検索は全体的にO(n)時間で完了します。
Oleg Afanasyev 2018年

1
私は期待to_setO(N LOGN)が複数セットに変換アレイに必要な労力よりも異物感開始する十分な大きさの配列で上回る開始する
Andrius Chamentauskas

1
これは役に立ちますが、それ自体は本当に答えではありませんか?おそらくこれを既存のソリューションに追加するほうがいいでしょうか?
SRack

18

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

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


2
この場合、違いは壊れていますa = [1、2、3] b = [1、2、3、4、5] a.difference(b).any?=> false
error-404


8

期待どおりに[: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

なぜa.sort == b.sort彼が頻度を気にするのではないのですか?
fl00r

4
@ fl00rアイテムが比較できない場合はどうなりますか?["", :b].frequency == [:b, ""].frequency #=> true
Victor Moroz

2
また、次のように機能することもできますa.group_by{|i| i} == b.group_by{|i| i}
fl00r

7

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

( array1 & array2 ) == array1

説明:&この場合の演算子は、a1のコピーを返しますが、a2にないアイテムは元のa1と同じですが、両方の配列の内容が同じで重複がない場合に限ります。

分析:順序が変更されていないことを考えると、これは二重反復として一貫して実装されていると思いますO(n*n)。特に、大規模配列のa1.sort == a2.sort場合、ワーストケースで実行するよりも悪いと思いますO(n*logn)


2
常に動作しません:a1 = [1,2,3], a2 = [2, 1, 3] a1 && a2リターン[2,1,3]と等しくされていない私のためにa1
カルヤンラグー

@Kaylan、それはときにのみ機能するという意味a1==a2ですか?array1等式の右側がで置き換えられた場合に機能する可能性array2がありますが、によって返される要素の順序&が保証されているかどうかは疑問です。
Cary Swoveland 16年

1
@KalyanRaghu &は配列の集合交差演算子であり、&&論理ANDです-それらは非常に異なります!
キンボール

2

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

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

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


@Victor Moroz、その通りで、度数は単純にO(n)になります。
Ron

2

組み合わせる&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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.