Я использую Ruby 1.8.6 с Rails 1.2.3, и мне нужно определить, имеют ли два массива одинаковые элементы, независимо от того, находятся ли они в одном порядке или нет. Гарантируется, что один из массивов не будет содержать дубликатов (другой может, и в этом случае ответ будет отрицательным).
Моя первая мысль была
require 'set'
a.to_set == b.to_set
но мне было интересно, есть ли более эффективный или идиоматический способ сделать это.
ruby
arrays
comparison
Таймон
источник
источник
[1,2]
и[2,1,1]
имеют ли одни и те же элементы?)difference
решение, которое предлагает очень быстрое и удобочитаемое решение. Больше информации здесь.Ответы:
Это не требует преобразования для установки:
источник
.uniq.sort
тогда? К томуuniq
же похоже наto_set
внутренне плюс дополнительный.to_a.sort
uniq
s. На самом деле я закончил тем, что создал один из массивовRange#to_a
, поэтому мне оставалось только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?
источник
A=[1]
иB=[1,1]
, оба(A-B)
и(B-A)
вернутся пустыми. См. Документацию по массивам .a.to_set == b.to_set
а принятый ответ использует,a.uniq.sort == b.uniq.sort
и оба дают тот же результат, что и((A-B) + (B-A)).blank?
для A = [1] и B = [1,1] согласны? Поскольку он просто просил улучшить свое исходное решение, мое исходное решение все еще работает :). дать согласие?A = [123, "test", [], some_object, nil]
иB = A#because I am lazy
, тогдаA.uniq.sort
будет выдана ошибка (сравнение строки и массива не выполнено).A = [1, 1, 2]
иB = [1, 2, 2]
Сравнение скорости
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
источник
sort
на скоростьto_set
что начну работать лучше с достаточно большими массивами, где O (n logn) начнет иметь большее значение, чем усилия, необходимые для преобразования массива в набор,Рубин 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
иb
естьComparable
,Исправление ответа @ mori на основе комментария @ steenslag
источник
a
иb
можно сортировать.Если вы ожидаете
[: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
если он заботится о частоте?["", :b].frequency == [:b, ""].frequency #=> true
a.group_by{|i| i} == b.group_by{|i| i}
Если вы знаете, что массивы имеют одинаковую длину и ни один из них не содержит дубликатов, это тоже работает:
Объяснение:
&
оператор в этом случае возвращает копию a1 SANs пункты , не найденную в а2, которая является такой же , как оригинал a1 тогда и только тогда оба массива имеют одинаковое содержимое без каких - либо дубликатов.Анализ: Учитывая, что порядок не изменился, я предполагаю, что это реализовано как двойная итерация так последовательно
O(n*n)
, заметно хуже для больших массивов, чем та,a1.sort == a2.sort
которая должна работать в худшем случаеO(n*logn)
.источник
a1 = [1,2,3], a2 = [2, 1, 3]
a1 && a2
возвращается[2,1,3]
для меня, которого нетa1
a1==a2
? Это может сработать, еслиarray1
в правой части равенства заменить наarray2
, но я сомневаюсь, что порядок элементов, возвращаемых с помощью&
, гарантирован.&
- это оператор пересечения множеств для массивов,&&
логический И - они очень разные!комбинирование
&
и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
источник
Один из подходов - перебрать массив без дубликатов.
# assume array a has no duplicates and you want to compare to b !a.map { |n| b.include?(n) }.include?(false)
Это возвращает массив истин. Если появляется любое ложное, то внешний
include?
вернет истину. Таким образом, вам нужно перевернуть все, чтобы определить, соответствует ли это совпадению.источник