ruby:如何有效地迭代哈希中的元素

我有一个非常大的哈希,我想迭代它。 Hash.each似乎太慢了。 有没有有效的方法来做到这一点?

如何将此哈希转换为数组?


在每个循环中,我正在做非常简单的字符串:

 name_hash.each {|name, str| record += name.to_s + "\|" + str +"\n" } 

并且哈希使用人名作为键,一些相关内容作为值:

 name_hash = {:"jose garcia" => "ca:tw#2@1,2@:th#1@3@;ar:tw#1@4@:fi#1@5@;ny:tw#1@6@;"} 

请考虑以下示例,该示例使用100万个元素的哈希值:

 #! /usr/bin/env ruby require 'benchmark' h = {} 1_000_000.times do |n| h[n] = rand end puts Benchmark.measure { h.each { |k, v| } } a = nil puts Benchmark.measure { a = h.to_a } puts Benchmark.measure { a.each { |k, v| } } 

我在我的系统上运行它(运行Ruby 1.8.5),我得到:

  0.350000 0.020000 0.370000 ( 0.380571) 0.300000 0.020000 0.320000 ( 0.307207) 0.160000 0.040000 0.200000 ( 0.198388) 

因此迭代数组确实更快(0.16秒对比散列0.35秒)。 但是生成arrays需要0.3秒。 因此净过程较慢0.46秒而0.35秒。

所以看起来最好只是迭代哈希,至少在这个测试用例中。

String#+很慢。 这应该改善它

  record = name_hash.map{|line| line.join("|")}.join("\n") 

如果你使用它输出到某个地方,你不应该创建一个巨大的字符串,而是逐行写入输出。

在ruby中这样做的更惯用的方法:

 record = name_hash.map{|k,v| "#{k}|#{v}"}.join("\n") 

我不知道这会与速度相比如何,但部分问题可能是因为你不断在字符串上添加一点并在每次迭代时创建新的(越来越长的)字符串对象。 连接在C中完成,可能表现更好。

迭代大型集合很慢,每种方法都不会限制它。 在你的循环中你做的那么慢? 如果需要转换为数组,可以通过调用some_hash.to_a

我曾经认为ruby 1.9.x已经使哈希迭代更快但可能是错误的。 如果它是简单的结构,你可以尝试不同的哈希,比如https://github.com/rdp/google_hash ,这是我为了让#each更可靠而破解的那个…

可能“通过进行单个数据库查询”

将大Hash转换为Array需要创建一个大对象,并且需要两次迭代,尽管其中一个是解释器的内部并且可能非常快。

这不仅仅比迭代Hash更快,但它可能适用于大型对象。

查看标准库基准测试包,以便轻松测量运行时。

我还冒昧地猜测,这里真正的问题是你有一个类似Hash的ActiveRecord对象,它在枚举的每个循环中都会对你的数据库服务器进行往返。 您真正想要的是绕过AR并运行本机查询以在一次往返中一次性检索所有内容。