Ruby 1.8.6とRails 1.2.3を使用していますが、2つの配列が同じ順序であるかどうかに関係なく、2つの配列に同じ要素があるかどうかを確認する必要があります。配列の1つは重複を含まないことが保証されています(もう1つは可能性があり、その場合の答えはノーです)。
私の最初の考えは
require 'set'
a.to_set == b.to_set
しかし、私はそれを行うためのより効率的なまたは慣用的な方法があるかどうか疑問に思っていました。
Ruby 1.8.6とRails 1.2.3を使用していますが、2つの配列が同じ順序であるかどうかに関係なく、2つの配列に同じ要素があるかどうかを確認する必要があります。配列の1つは重複を含まないことが保証されています(もう1つは可能性があり、その場合の答えはノーです)。
私の最初の考えは
require 'set'
a.to_set == b.to_set
しかし、私はそれを行うためのより効率的なまたは慣用的な方法があるかどうか疑問に思っていました。
[1,2]
を[2,1,1]
持っていますか?)
回答:
これを設定するための変換は必要ありません。
a.sort == b.sort
.uniq.sort
、その後?その上uniq
、to_set
内部的に追加されたものに似ています.to_a.sort
uniq
s なしではあるが、私が最終的に使用したものに最も近いため、これを受け入れる。実際、私は配列の1つをで作成することRange#to_a
になったのでsort
、もう1つだけで済みました。
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を参照してください。
a.to_set == b.to_set
承認された回答が使用してa.uniq.sort == b.uniq.sort
おり、どちらも((A-B) + (B-A)).blank?
A = [1] とまったく同じ結果が得られますそしてB = [1,1]は同意しますか?彼は元の解決策の改善を求めていたので、私の元の解決策はまだ機能しています:)。同意する?
A = [123, "test", [], some_object, nil]
とするとB = A#because I am lazy
、A.uniq.sort
エラーがスローされます(文字列と配列の比較に失敗しました)。
A = [1, 1, 2]
、B = [1, 2, 2]
速度比較
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
速度に影響しません
to_set
O(N LOGN)が複数セットに変換アレイに必要な労力よりも異物感開始する十分な大きさの配列で上回る開始する
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
それが誰かを助けることを願っています!
期待どおりに[: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
彼が頻度を気にするのではないのですか?
["", :b].frequency == [:b, ""].frequency #=> true
a.group_by{|i| i} == b.group_by{|i| i}
配列の長さが等しく、どちらの配列にも重複が含まれていないことがわかっている場合、これも機能します。
( array1 & array2 ) == array1
説明:&
この場合の演算子は、a1のコピーを返しますが、a2にないアイテムは元のa1と同じですが、両方の配列の内容が同じで重複がない場合に限ります。
分析:順序が変更されていないことを考えると、これは二重反復として一貫して実装されていると思いますO(n*n)
。特に、大規模配列のa1.sort == a2.sort
場合、ワーストケースで実行するよりも悪いと思いますO(n*logn)
。
a1 = [1,2,3], a2 = [2, 1, 3]
a1 && a2
リターン[2,1,3]
と等しくされていない私のためにa1
a1==a2
ですか?array1
等式の右側がで置き換えられた場合に機能する可能性array2
がありますが、によって返される要素の順序&
が保証されているかどうかは疑問です。
&
は配列の集合交差演算子であり、&&
論理ANDです-それらは非常に異なります!
組み合わせる&
と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