我有以下情况。我有一大堆随机字符串。该数组应尽可能快地独特。
现在通过一些基准测试,我发现ruby的uniq很慢:
require 'digest'
require 'benchmark'
#make a nice random array of strings
list = (1..100000).to_a.map(&:to_s).map {|e| Digest::SHA256.hexdigest(e)}
list += list
list.shuffle
def hash_uniq(a)
a_hash = {}
a.each do |v|
a_hash[v] = nil
end
a_hash.keys
end
Benchmark.bm do |x|
x.report(:uniq) { 100.times { list.uniq} }
x.report(:hash_uniq) { 100.times { hash_uniq(list) } }
end
要点 - > https://gist.github.com/stillhart/20aa9a1b2eeb0cff4cf5
结果非常有趣。可能是红宝石的uniq很慢吗?
user system total real
uniq 23.750000 0.040000 23.790000 ( 23.823770)
hash_uniq 18.560000 0.020000 18.580000 ( 18.591803)
现在我的问题:
有没有更快的方法让数组独一无二?
我做错了吗?
Array.uniq方法有什么问题吗?
我正在使用ruby 2.2.3p173(2015-08-18修订版51636)[x86_64-linux]
答案 0 :(得分:3)
对大型数据集的字符串解析操作肯定不是Ruby所发挥的作用。如果这对业务至关重要,您可能希望在C或Go之类的内容中编写扩展,或者让其他应用程序在将其传递给Ruby应用程序之前处理它。
那就是说。您的基准测试似乎有些奇怪。使用Ruby 2.2.3
在我的MacBook Pro上运行相同的操作会产生以下结果:
user system total real
uniq 10.300000 0.110000 10.410000 ( 10.412513)
hash_uniq 11.660000 0.210000 11.870000 ( 11.901917)
建议uniq
稍快一些。
如果可能,您应该始终尝试使用正确的集合类型。如果您的收藏品真的与众不同,请使用Set。它们具有更好的内存配置文件,Hash
的查找速度更快,同时保留了一些Array
直觉。
但是,如果您的数据已经在Array
,那么这可能不是一个很好的权衡,因为插入Set
的速度相当慢,正如您在此处所见:
user system total real
uniq 11.040000 0.060000 11.100000 ( 11.102644)
hash_uniq 12.070000 0.230000 12.300000 ( 12.319356)
set_insertion 12.090000 0.200000 12.290000 ( 12.294562)
我添加了以下基准:
x.report(:set_insertion) { 100.times { Set.new(list) } }