Ruby on rails ruby:如何高效地迭代散列中的元素
我有一个非常大的散列,我想迭代它。散列。每个看起来都太慢了。 有什么有效的方法可以做到这一点吗 把这个散列转换成数组怎么样 在每个循环中,我都在做非常简单的字符串工作:Ruby on rails ruby:如何高效地迭代散列中的元素,ruby-on-rails,ruby,arrays,hash,Ruby On Rails,Ruby,Arrays,Hash,我有一个非常大的散列,我想迭代它。散列。每个看起来都太慢了。 有什么有效的方法可以做到这一点吗 把这个散列转换成数组怎么样 在每个循环中,我都在做非常简单的字符串工作: 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#
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@;"}
迭代大型集合的速度很慢,每个方法都不是限制它的因素。你在做什么,这么慢?如果需要转换为数组,可以通过调用一些散列来实现。要想在大型集合上迭代很慢,each方法并不是限制它的方法。你在做什么,这么慢?如果您需要转换为数组,您可以通过调用一些\u hash.to\u a来实现这一点,可能需要进行单个db查询 将大型散列转换为数组需要创建一个大型对象,并且需要两次迭代,尽管其中一次迭代是解释器内部的,并且可能非常快 这不太可能比在散列上迭代更快,但对于大型对象可能更快 查看一个测量运行时的简单方法 我还想大胆猜测,这里真正的问题是,您有一个类似于哈希的ActiveRecord对象,它在枚举的每个周期中对db服务器施加一个往返。您真正想要的可能是绕过AR并运行本机查询,以便在一次往返中一次检索所有内容。可能是通过进行一次db查询 将大型散列转换为数组需要创建一个大型对象,并且需要两次迭代,尽管其中一次迭代是解释器内部的,并且可能非常快 这不太可能比在散列上迭代更快,但对于大型对象可能更快 查看一个测量运行时的简单方法
我还想大胆猜测,这里真正的问题是,您有一个类似于哈希的ActiveRecord对象,它在枚举的每个周期中对db服务器施加一个往返。您真正想要的可能是绕过AR,运行一个本机查询,在一次往返中一次检索所有内容。我原以为ruby 1.9.x加快了哈希迭代,但可能是错误的。如果是简单的结构,你可以尝试一个不同的散列,就像我为了使每一个更可靠而破解的一样…我原以为ruby 1.9.x使散列迭代更快,但可能是错的。如果是简单的结构,你可以尝试不同的散列,比如我为了使每个散列更可靠而对其进行了黑客攻击…考虑以下示例,该示例使用了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.35秒慢0.46秒
因此,至少在本测试用例中,似乎最好只对哈希进行迭代。考虑以下示例,该示例使用了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.35秒慢0.46秒
因此,至少在这个测试用例中,似乎最好只对散列进行迭代。在ruby中更惯用的方法是:
record = name_hash.map{|k,v| "#{k}|#{v}"}.join("\n")
我不知道这与速度相比会如何,但问题的一部分可能是因为您不断在字符串上添加一点,并在每次迭代中创建新的更长的字符串对象。连接是在C中完成的,可能会执行得更好。在ruby中更惯用的方法是:
record = name_hash.map{|k,v| "#{k}|#{v}"}.join("\n")
我不知道这与速度相比会如何,但问题的一部分可能是因为您不断在字符串上添加一点,并在每次迭代中创建新的更长的字符串对象。连接是在C中完成的,可能会执行得更好。String+速度较慢。这应该会改善它
record = name_hash.map{|line| line.join("|")}.join("\n")
如果您使用它来输出到某个地方,您不应该创建一个巨大的字符串,而是应该逐行写入输出。string+很慢。这应该会改善它
record = name_hash.map{|line| line.join("|")}.join("\n")
如果你用它输出到某个地方,你不应该创建一个巨大的字符串,而应该逐行写入输出。我试过了。每个1M记录哈希都需要5个多小时。我问你是否尝试过你认为是解决方案的方法。哈希迭代本身应该很快。在Ruby 2x中,它是通过一个链接链实现的,用于保持良好的订单属性。迭代过程中正在做什么?100万-100万是一个相当多的项目,因此,即使每个项目需要0.01秒或100/秒,也需要2.7小时。也就是说,问题可能在每个模块内部,而不是每个方法/iter
它本身就是一个例子。也许有更好的方法来解决这个问题?请包含完整的相关代码。正如djconnel在回答中所示,实际的迭代非常快。因此,人们高度怀疑在每个块内部所做的事情是瓶颈。DigitalRoss还建议,如果散列数据来自或利用数据库/模型本身,可能会有一个更好/完全不同的解决方案..一个没有被问到的问题是,您使用的机器上有多少可用RAM?100万条记录的5个小时似乎很长,除非你所在的机器受到内存限制,并且正在交换。我试过了。每100万条记录的哈希需要5个多小时。我想问你是否尝试过你认为是解决方案的方法。哈希迭代本身应该很快。在Ruby 2x中,它是通过一个链接链实现的,用于保持良好的订单属性。迭代过程中正在做什么?100万-100万是一个相当多的项目,因此,即使每个项目需要0.01秒或100/秒,也需要2.7小时。也就是说,问题可能在每个块内部,而不是每个方法/迭代本身。也许有更好的方法来解决这个问题?请包含完整的相关代码。正如djconnel在回答中所示,实际的迭代非常快。因此,人们高度怀疑在每个块内部所做的事情是瓶颈。DigitalRoss还建议,如果散列数据来自或利用数据库/模型本身,可能会有一个更好/完全不同的解决方案..一个没有被问到的问题是,您使用的机器上有多少可用RAM?100万条记录的5个小时似乎很长,除非您所在的计算机受到内存限制并且正在交换。为什么将哈希转换为数组需要大量新对象?此外,在文章中没有明确指出数据来自[关系]数据库..嗯,既然你提到了它,大多数对象将被重用,或者它们将是不可变的内联值。我会更新答案。至于db,他确实用Rails标记了这个问题,而报道的时间似乎太慢了,不可能是其他任何事情。我不是说这不是什么。。傻乎乎的:希望我在主帖子上的评论能提供更多信息。@DigitalRoss我没有使用AR。它只是在处理一个txt文件。那么为什么这个标签是ruby on rails?为什么将哈希转换为数组需要大量新对象?此外,在文章中没有明确指出数据来自[关系]数据库..嗯,既然你提到了它,大多数对象将被重用,或者它们将是不可变的内联值。我会更新答案。至于db,他确实用Rails标记了这个问题,而报道的时间似乎太慢了,不可能是其他任何事情。我不是说这不是什么。。傻乎乎的:希望我在主帖子上的评论能提供更多信息。@DigitalRoss我没有使用AR。它只是在处理一个txt文件。那么为什么这个标签是ruby on rails?所有发布的数字都短于5小时;-+1个用于小基准;虽然它们很小,但它们清楚地表明问题不在于哈希或数组的实现。。这意味着性能瓶颈来自于每个块内部的操作。哇,Ruby 1.8.5?!为什么这么老?Redhat Enterprise Linux版本5。。。我们的代码相当成熟,因为我从事的是支持工作,而不是开发工作,而且我们的升级速度很慢。所有发布的数字都短于5小时;-+1个用于小基准;虽然它们很小,但它们清楚地表明问题不在于哈希或数组的实现。。这意味着性能瓶颈来自于每个块内部的操作。哇,Ruby 1.8.5?!为什么这么老?Redhat Enterprise Linux版本5。。。我们的代码相当成熟,因为我从事的是支持工作,而不是开发工作,而且我们的升级速度很慢。我甚至比我的答案更喜欢这一点!对于任何想知道这和我的答案有什么区别的人,使用一个参数调用map会生成一个数组,[key,value]。我发布的双参数示例只是直接分配键/值。{}比String+快,但我不确定哪个版本的block param更快。我甚至比我的答案更喜欢它!对于任何想知道这和我的答案有什么区别的人,使用一个参数调用map会生成一个数组,[key,value]。我发布的双参数示例只是直接分配键/值。{}比String+快,但我不确定哪个版本的block param更快。您的答案也不错。{…}优于+。我去掉了反斜杠,因为它不会显示在输出中。您的答案也很好。{…}优于+。我去掉了反斜杠,因为它不会显示在输出中。