두 배열의 내용이 동일한 지 (순서에 관계없이) 확인


90

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

내 첫 생각은

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

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



시도 array.should = ~ another_array check stackoverflow.com/questions/2978922/…
Athena

다음과 같은 방법으로 많은 혼란을 줄일 수 있습니다. 1) 배열의 요소가 반드시 정렬 가능한지 여부를 지정합니다. 2) (예를 들어, 할 "두 배열이 동일한 요소가 있는지 여부를"당신이 무슨 뜻인지 명확히하기 위해 간단한 예제를 제공 [1,2]하고 [2,1,1]? 같은 요소가)
캐리 Swoveland

difference매우 빠르고 읽기 쉬운 솔루션을 제공하는 Ruby 2.6이 도입되었습니다 . 여기에 더 많은 정보가 있습니다.
SRack

답변:


140

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

a.sort == b.sort

변환이 없습니까? 그러면 무엇입니까 .uniq.sort? 게다가 uniq유사하다 to_set내부 및 추가.to_a.sort
빅터 Moroz

uniqs 없이도 내가 사용한 것과 가장 가깝기 때문에 이것을 수락합니다 . 실제로 나는를 사용하여 배열 중 하나를 만들었 Range#to_a으므로 sort다른 하나만 사용했습니다.
Taymon 2012-06-07

11
배열에 단순히 정렬 할 수없는 요소 (예 : 해시 배열)가 포함되어 있으면 작동하지 않습니다. sahil dhankhar의 솔루션이보다 일반적인 솔루션 인 것으로 보입니다.
brad

40

두 배열 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?


두 배열 중 하나에 중복 항목이 있으면 실패합니다. 예를 들어, if A=[1]B=[1,1], 둘 다 (A-B)(B-A)공백을 반환합니다. 어레이 문서를 참조하십시오 .
jtpereyda 2013 년

@dafrazzman은 당신과 전적으로 동의합니다. 귀하의 의견을 반영하기 위해 내 답변을 수정했습니다. 그러나 질문 (또는 수락 된 답변)을 자세히 살펴보면 asker는 다음을 사용 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 lazy다음 A.uniq.sort오류가 발생합니다 (문자열과 배열의 비교에 실패했습니다).
Automatico

배열 크기에 따라 다르기 때문에 이것이 O (n)일까요? (선형)
user3007294

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

elemetns의 btw 순서는 sort의 속도에 영향을주지 않습니다
Morozov

놀랐습니다 ... 세트 조회 O (n) 시간 복잡성으로 인해 다른 모든 비교를 능가 할 것으로 예상 했습니다 . 따라서 잘 구현 된 정렬에는 O (n logn)가 필요합니다. 세트로 캐스팅하고 값을 찾는 것은 전체적으로 O (n) 시간에 이루어집니다.
Oleg Afanasyev

1
to_setO (n logn)이 어레이를 세트로 변환하는 데 필요한 노력보다 더 중요하기 시작하는 충분히 큰 어레이로 성능을 능가하기 시작할 것으로 예상 합니다
Andrius Chamentauskas

1
이것은 도움이되지만 그 자체로는 답이 아닙니다. 아마도 이것을 기존 솔루션에 추가하는 것이 더 낫습니까?
SRack 19

19

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

누군가에게 도움이되기를 바랍니다!


4
이 경우 차이가 깨집니다 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 2012

2
또한이 같은 기능 뭔가 할 수a.group_by{|i| i} == b.group_by{|i| i}
fl00r

7

배열의 길이가 같고 배열에 중복 항목이 포함되어 있지 않다는 것을 알고 있으면 다음과 같이 작동합니다.

( array1 & array2 ) == array1

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

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


2
항상 작동하지 않습니다 a1 = [1,2,3], a2 = [2, 1, 3] a1 && a2반환 [2,1,3]나를 위해에 동일하지 않은a1
칼리 라구

@Kaylan, 당신은 그것이 때만 작동한다는 것을 의미하지 a1==a2않습니까? array1평등의 오른쪽이로 바뀌면 작동 할 수 array2있지만에서 반환되는 요소의 순서 &가 보장되지는 않습니다.
Cary Swoveland

1
@KalyanRaghu &는 배열에 대한 집합 교차 연산자 &&이며 논리적이며 매우 다릅니다!
Kimball

3

결합 &하고 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

2

한 가지 접근 방식은 중복없이 어레이를 반복하는 것입니다.

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

이것은 true의 배열을 반환합니다. 거짓이 나타나면 외부 include?는 참을 반환합니다. 따라서 일치 여부를 결정하기 위해 전체를 뒤집어 야합니다.


@Victor Moroz, 맞아요. 그리고 빈도 수는 단순히 O (n)입니다.
Ron
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.