101

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

私の最初の考えは

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

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

4

9 に答える 9

151

これは、設定への変換を必要としません:

a.sort == b.sort
于 2012-06-06T18:34:50.343 に答える
42

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` 

::::::::::: 編集 :::::::::::::

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

于 2012-12-23T14:36:41.137 に答える
24

速度比較

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
于 2016-04-21T12:09:52.420 に答える
17

aとの要素が のb場合Comparable

a.sort == b.sort

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

于 2014-02-25T04:41:56.783 に答える
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
于 2012-06-06T18:27:08.160 に答える
7

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

( array1 & array2 ) == array1

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

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

于 2013-02-20T13:56:55.000 に答える
2

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

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

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

于 2012-06-06T18:30:32.277 に答える