두 배열의 내용이 동일한 지 (순서에 관계없이) 확인 중 하나는 중복을 포함하지 않도록 보장됩니다

Rails 1.2.3과 함께 Ruby 1.8.6을 사용하고 있으며 두 배열이 동일한 순서인지 여부에 관계없이 동일한 요소를 가지고 있는지 확인해야합니다. 배열 중 하나는 중복을 포함하지 않도록 보장됩니다 (다른 하나는 대답이 아니오 인 경우).

내 첫 생각은

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

하지만 더 효율적이거나 관용적 인 방법이 있는지 궁금합니다.



답변

다음을 설정하기 위해 변환 할 필요가 없습니다.

a.sort == b.sort


답변

두 배열 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 연산자를 사용하고 있으며 중복을 마스킹합니다.). 그러나 여전히 중복이 관심사 인 경우 카운트 확인을 추가하면 동일하게 수정됩니다 (질문에 따라 하나의 배열 만 중복을 포함 할 수 있음). 따라서 최종 솔루션은 다음과 같습니다.
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


답변

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및 의 요소 bComparable이면

a.sort == b.sort

@steenslag의 의견을 기반으로 @mori의 답변 수정


답변

예상하면 [: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

설명 :& 이 경우 운영자가 두 배열이 중복되지 같은 내용을 IFF에 원래 A1과 동일 A1 산세의 사본 모든 항목 A2에서 찾을 수 없습니다를 반환합니다.

분석 : 순서가 변경되지 않았다는 점을 감안할 때, 이것이 최악의 경우에 수행해야하는 O(n*n)것보다 큰 배열의 경우 특히 더 나쁘게 일관되게 이중 반복으로 구현되었다고 생각합니다 .a1.sort == a2.sortO(n*logn)