检查两个数组是否具有相同的内容(按任何顺序)

Tay*_*mon 83 ruby arrays comparison

我正在使用带有Rails 1.2.3的Ruby 1.8.6,并且需要确定两个数组是否具有相同的元素,无论它们是否处于相同的顺序.保证其中一个数组不包含重复项(另一个可能,在这种情况下答案是否定的).

我的第一个想法是

require 'set'
a.to_set == b.to_set
Run Code Online (Sandbox Code Playgroud)

但我想知道是否有更有效或惯用的方式.

Mor*_*ori 132

这不需要转换为设置:

a.sort == b.sort
Run Code Online (Sandbox Code Playgroud)

  • 省略`uniq`s,他们掩盖重复. (31认同)
  • 如果数组包含无法简单排序的元素(例如散列数组),则无效.sahil dhankhar的解决方案似乎是一个更通用的解决方案. (9认同)

Sah*_*har 38

对于两个数组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` 
Run Code Online (Sandbox Code Playgroud)

:::::::::::编辑::::::::::::::

正如评论中所建议的那样,上述解决方案无法复制.虽然问题甚至不需要,因为提问者对重复不感兴趣(他在检查之前将他的数组转换为设置并且掩盖重复,即使你看了在检查之前他正在使用.uniq运算符的加速答案,这也掩盖了重复.)但是,如果重复你感兴趣,只需添加一个计数检查将修复相同(根据问题只有一个数组可以包含重复).所以最终的解决方案是: A.size == B.size and ((A-B) + (B-A)).blank?


Mor*_*zov 19

速度比较

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
Run Code Online (Sandbox Code Playgroud)

  • 我希望 `to_set` 开始在足够大的数组上表现出色,其中 O(n logn) 开始比将数组转换为 set 所需的努力更重要 (2认同)

Jar*_*eck 15

当的元件abComparable,

a.sort == b.sort
Run Code Online (Sandbox Code Playgroud)

根据@ steenslag的评论纠正@ mori的答案

  • ......当`a`和`b`可以排序时. (4认同)

SRa*_*ack 10

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
Run Code Online (Sandbox Code Playgroud)

运行基准测试:

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
Run Code Online (Sandbox Code Playgroud)

希望能对某人有所帮助!

  • 在这种情况下,差异是破坏的 a = [1, 2, 3] b = [1, 2, 3, 4, 5] a.difference(b).any? => 假 (11认同)

Vic*_*roz 7

如果你期望[: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
Run Code Online (Sandbox Code Playgroud)

  • @ fl00r如果物品不具有可比性怎么办?`["",:b] .frequency == [:b,""] .frequency#=> true` (4认同)
  • 你也可以做一些像'a.group_by {| i | i} == b.group_by {| i | 我}` (2认同)

Nat*_*Nat 6

如果您知道数组长度相等且两个数组都不包含重复项,那么这也适用:

( array1 & array2 ) == array1
Run Code Online (Sandbox Code Playgroud)

说明:&在这种情况下,运算符返回a1的副本,而不是在a2中找到的任何项目,如果两个数组具有相同的内容且没有重复项,则与原始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` (2认同)
  • @KalyanRaghu `&` 是数组的集合交集运算符,`&&` 是逻辑 AND - 它们非常不同! (2认同)

Tod*_*oki 5

结合起来&size可能很快。

\n\n
require \'benchmark/ips\'\nrequire \'set\'\n\nBenchmark.ips do |x|\n  x.report(\'sort\')   { a.sort == b.sort }  \n  x.report(\'sort!\')  { a.sort! == b.sort! }  \n  x.report(\'to_set\') { a.to_set == b.to_set }  \n  x.report(\'minus\')  { ((a - b) + (b - a)).empty? }\n  x.report(\'&.size\') { a.size == b.size && (a & b).size == a.size }  \nend  \n\nCalculating -------------------------------------\n                sort    896.094k (\xc2\xb111.4%) i/s -      4.458M in   5.056163s\n               sort!      1.237M (\xc2\xb1 4.5%) i/s -      6.261M in   5.071796s\n              to_set    224.564k (\xc2\xb1 6.3%) i/s -      1.132M in   5.064753s\n               minus      2.230M (\xc2\xb1 7.0%) i/s -     11.171M in   5.038655s\n              &.size      2.829M (\xc2\xb1 5.4%) i/s -     14.125M in   5.010414s\n
Run Code Online (Sandbox Code Playgroud)\n