私はRuby 1.8.6 with Rails 1.2.3を使用しており、2つの配列が同じ要素を持っているかどうかにかかわらず、同じ順序になっています。配列の1つに重複が含まれないことが保証されています(他の配列は、その場合、答えはノーです)。
私の最初の考えは
require 'set'
a.to_set == b.to_set
しかし、もっと効率的または慣用的な方法があるのだろうかと思っていました。
これは設定するために変換を必要としません:
a.sort == b.sort
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?
スピード比較
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
[: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
配列の長さが同じで、どちらの配列にも重複が含まれていないことがわかっている場合、これも機能します。
_( array1 & array2 ) == array1
_
説明:この場合の_&
_演算子は、a2で見つからない項目を除くa1のコピーを返します。これは、両方の配列が同じコンテンツを重複なしで持っている場合、元のa1と同じです。
Analyis:順序は変わらないので、これは一貫してO(n*n)
のように二重反復として実装されていると推測します。特に、大きい配列では_a1.sort == a2.sort
_よりも悪い最悪の場合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
それが誰かを助けることを願っています!
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を返します。したがって、全体を反転させて、一致するかどうかを判断する必要があります。
結合&
と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