1

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

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


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

name_hash.each {|name, str|

  record += name.to_s + "\|" + str +"\n"

}

而hash使用人名作为key,一些相关的内容作为value:

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

6 回答 6

4

考虑以下示例,该示例使用 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 秒)。但是生成数组需要 0.3 秒。所以净过程慢了 0.46 秒,而 0.35 秒。

所以似乎最好只迭代哈希,至少在这个测试用例中。

于 2012-08-15T23:18:29.313 回答
2

在 ruby​​ 中更惯用的方法是:

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

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

于 2012-08-15T23:51:24.700 回答
2

String#+是缓慢的。这应该改进它

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

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

于 2012-08-15T23:52:32.880 回答
1

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

于 2012-08-15T22:50:13.020 回答
1

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

将大哈希转换为数组需要创建一个大对象,并且需要两次迭代,尽管其中一个在解释器内部并且可能非常快。

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

查看Standard Library Benchmark 包,了解测量运行时间的简单方法。

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

于 2012-08-15T23:08:00.200 回答
1

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

于 2012-08-15T23:16:37.317 回答