我的第一反应是:
require 'set'
a.to_set == b.to_set
不过我想知道有没有更加高效或者习惯的方法可以做到这件事。
require 'set'
a.to_set == b.to_set
不过我想知道有没有更加高效或者习惯的方法可以做到这件事。
这不需要进行转换即可设置:
a.sort == b.sort
.uniq.sort
是什么意思呢?除了uniq
在内部类似于to_set
外,还有额外的.to_a.sort
。 - Victor Morozuniq
。实际上,我最终使用了 Range#to_a
创建其中一个数组,所以我只需要对另一个数组进行 sort
操作。 - Taymon对于两个数组 A 和 B:
如果 (A-B).blank? and (B-A).blank?
,则 A 和 B 具有相同的内容。
或者你可以检查 ((A-B) + (B-A)).blank?
。
另外,正如 @cort3z 建议的那样,该解决方案也适用于多态数组,即
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.to_set == b.to_set
,而接受的答案正在使用a.uniq.sort == b.uniq.sort
,并且两者都与((A-B) + (B-A)).blank?
给出完全相同的结果,对于A=[1]和B=[1,1],你同意吗?既然他只是在寻求对他原始解决方案的改进,那么我的原始解决方案仍然有效:)。你同意吗? - Sahil DhankharA = [123, "test", [], some_object, nil]
和 B = A#because I am lazy
,那么 A.uniq.sort
就会抛出错误(字符串和数组的比较失败)。 - AutomaticoA = [1, 1, 2]
和 B = [1, 2, 2]
。 - BoudiRuby 2.6+
在Ruby 2.6中引入了 difference
方法。
这提供了一个非常快速、易读的解决方案,如下所示:
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 = [1, 2, 3]
b = [1, 2, 3, 4, 5, 6]
a.difference(b).any?
# => false
这意味着要获取双向差异,需要运行:
a.difference(b).any? || b.difference(a).any?
运行基准测试:
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? }
x.report('difference two way') { a.difference(b).any? || b.difference(a).any? }
end
sort 10.175k (± 6.2%) i/s - 50.778k in 5.015112s
sort! 10.513k (± 6.8%) i/s - 53.212k in 5.089106s
to_set 4.953k (± 8.8%) i/s - 24.570k in 5.037770s
minus 15.290k (± 6.6%) i/s - 77.520k in 5.096902s
difference 25.481k (± 7.9%) i/s - 126.600k in 5.004916s
difference two way 12.652k (± 8.3%) i/s - 63.232k in 5.038155s
我的理解是,difference
是一个很好的选择来进行单向的差异比较。
如果需要双向检查,则需要在性能和可读性之间做出权衡。对我而言,可读性更重要,但这是需要根据具体情况来决定的。
希望这对某些人有所帮助!
速度比较
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
to_set
方法能够开始表现出更好的性能。 - Andrius Chamentauskasminus
中,建立联合是可惜的。(a - b).empty? && (b - a).empty?
。 - undefineda
和 b
能够被排序时。 - Cary Swoveland[: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["", :b].frequency == [:b, ""].frequency #=> true
- Victor Moroza.group_by{|i| i} == b.group_by{|i| i}
这样的功能。 - fl00r( array1 & array2 ) == array1
说明:在这种情况下,&
运算符返回 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
不相等。 - Kalyan Raghua1==a2
时才能正常工作?如果将等式右侧的array1
替换为array2
,它可能会起作用,但我怀疑&
返回的元素顺序是否得到保证。 - Cary Swoveland&
是数组的集合交集运算符,&&
是逻辑 AND 运算符 - 它们非常不同! - Kimball结合使用&
和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
Set Intersection — 返回一个包含两个数组共有的唯一元素的新数组。顺序保持与原始数组相同。
- buncis一种方法是在没有重复项的情况下遍历数组
# assume array a has no duplicates and you want to compare to b
!a.map { |n| b.include?(n) }.include?(false)
这将返回一个由true组成的数组。如果出现任何false,则外部的include?
将返回true。因此,您必须反转整个过程以确定它是否匹配。
b
包含a
的所有元素以及一些额外元素时,这种方法将无法运行。 - Toby 1 Kenobi
[1,2]
和[2,1,1]
是否具有相同的元素?) - Cary Swovelanddifference
,提供了一种非常快速和易读的解决方案。更多信息请参见此处。 - SRack