2012-06-06 3 views
61

Я использую Ruby 1.8.6 с Rails 1.2.3 и вам нужно определить, имеют ли два массива одинаковые элементы независимо от того, являются ли они в том же порядке. Один из массивов гарантированно не содержит дубликатов (другой может быть, и в этом случае ответ будет отрицательным).Проверьте, имеют ли два массива одинаковое содержимое (в любом порядке)

Моя первая мысль была

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

, но мне было интересно, если есть более эффективный или идиоматических способ сделать это.

+0

возможно дубликат [Рубин - Есть ли массив А содержат все элементы массива B] (Http: // StackOverflow.com/questions/5890717/ruby-do-array-a-contains-all-elements-of-array-b) – fl00r

+0

Попробуйте array.should = ~ another_array проверить http://stackoverflow.com/questions/2978922/rspec-array-should-another-array-but-without-concern-for-order – Athena

+0

Вы могли бы сэкономить много путаницы: 1) указать, являются ли элементы массивов обязательными для сортировки; и 2) дать простой пример, чтобы прояснить, что вы подразумеваете под этим термином: «имеют ли два массива одни и те же элементы» (например, '' [1,2] 'и' [2,1,1] 'имеют одинаковые элементы?) –

ответ

93

Это не требует преобразования, чтобы установить:

a.sort == b.sort 
+31

Оставьте «uniq's», они маскируют дубликаты. – steenslag

+0

Нет конверсии? Что такое '.uni.sort'? Кроме того, 'uniq' похож на' to_set' внутренне плюс дополнительный '.to_a.sort' –

+0

Принимая это, так как он ближе всего к тому, что я использовал, но без' uniq'. Фактически я закончил создание одного из массивов с «Range # to_a», поэтому мне пришлось только «сортировать» другой. – Taymon

6

Если вы ожидаете, что [: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 
+0

Почему не просто 'a.sort == b.sort', если он заботится о частоте? – fl00r

+3

@ fl00r Что делать, если предметы не сопоставимы? '[" ",: b] .frequency == [: b," "] .frequency # => true' –

+0

хорошая точка. В общем случае вы правы – fl00r

1

Один подход заключается в итерации по массиву, без дублей

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

Это возвращает массив истин. Если появится какое-либо ложь, внешний include? вернет true. Таким образом, вы должны инвертировать все это, чтобы определить, является ли это совпадением.

+2

Это было бы O (n^2) –

+0

@Victor Moroz, вы правы, а частотный счет будет просто O (n). – Ron

31

для двух массивов А и В: А и В имеют такое же содержание, если: (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 :::::::::::::

Как указывается в комментариях, выше решение не выполняется для duplicates.Although согласно вопрос, который даже не требуется, так как искатель не заинтересован в дубликатах (он преобразует свои массивы для установки перед проверкой, и это маскирует дубликаты, и даже если вы посмотрите на accepeted ответ, он использует оператор .uniq перед проверкой и это слишком маскирует дубликаты.). Но все же, если вас интересуют дубликаты, просто добавление проверки количества будет исправлять то же самое (по одному вопросу только один массив может содержать дубликаты). Таким образом, окончательное решение будет: A.size == B.size and ((A-B) + (B-A)).blank?

+0

Это не удастся, если любой массив содержит дубликаты. Например, если 'A = [1]' и 'B = [1,1]', оба '(A-B)' и '(B-A)' будут возвращать пустое. См. [Массивная документация] (http://www.ruby-doc.org/core-2.0.0/Array.html#method-i-2D). – jtpereyda

+0

@dafrazzman полностью согласен с вами. Я изменил свой ответ, чтобы включить ваши отзывы. Но если у вас есть близкий взгляд на вопрос (или принятый ответ), спрашивающий использует: 'a.to_set == b.to_set', и принятый ответ использует' a .uniq.sort == b.uniq.sort' и оба дают тот же результат, что и '((AB) + (BA)). blank?' для A = [1] и B = [1,1] согласны? Поскольку он просто просил улучшить свое оригинальное решение, мое оригинальное решение все еще работает :). дать согласие? –

+1

Это решение довольно приятно, поскольку оно обрабатывает объекты нескольких типов. Скажем, у вас есть A = [123, "test", [], some_object, nil] 'и' B = A #, потому что я ленив', тогда 'A.uniq.sort' будет вызывать ошибку (сравнение строки и массива не смогли). – Automatico

4

Если вы знаете, массивы имеют одинаковую длину и ни один массив содержит дубликаты, этот способ хорош

(array1 & array2) == array1 
+2

Не работает всегда: 'a1 = [1,2,3], a2 = [2, 1, 3]' 'a1 && a2' возвращает' [2,1,3] 'для меня, что не равный 'a1' –

+0

@ Кайлан, разве вы не имеете в виду, что он работает только когда' a1 == a2'? Он может работать, если 'array1' в правой части равенства заменяется на' array2', но я сомневаюсь, что порядок элементов, возвращаемых '&', гарантирован. –

13

Когда элементы a и b являются Comparable,

a.sort == b.sort 

Коррекция ответа @ Мори на основе @ steenslag замечании

+0

Nice и разумно. –

+3

... когда 'a' и' b' могут быть отсортированы. –

6

Скорость comparsions

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 
+0

btw порядок elemetns не влияет на скорость сортировки –