【发布时间】:2012-06-12 05:19:04
【问题描述】:
例如,我有单个哈希数组
a = [{a: :b}, {c: :d}]
将它转换成这个的最好方法是什么?
{a: :b, c: :d}
【问题讨论】:
例如,我有单个哈希数组
a = [{a: :b}, {c: :d}]
将它转换成这个的最好方法是什么?
{a: :b, c: :d}
【问题讨论】:
你可以使用
a.reduce Hash.new, :merge
直接产生
{:a=>:b, :c=>:d}
请注意,如果发生冲突,顺序很重要。后面的哈希会覆盖以前的映射,参见例如:
[{a: :b}, {c: :d}, {e: :f, a: :g}].reduce Hash.new, :merge # {:a=>:g, :c=>:d, :e=>:f}
【讨论】:
Hash.new,或者朋友喜欢叫他{} :-) 尽管我喜欢纯函数解决方案,但请注意merge 将在每次迭代时创建一个新的哈希;我们可以改用update(它不会弄乱输入哈希,这是重点):hs.reduce({}, :update)
:update 版本是更快的选择。
这两个:
total_hash = hs.reduce({}) { |acc_hash, hash| acc_hash.merge(hash) }
total_hash = hs.reduce({}, :merge)
请注意,Hash#merge 在每次迭代时都会创建一个新哈希,如果您正在构建一个大哈希,这可能会出现问题。在这种情况下,请改用update:
total_hash = hs.reduce({}, :update)
另一种方法是将散列转换为对,然后构建最终散列:
total_hash = hs.flat_map(&:to_a).to_h
【讨论】:
你可以使用.inject:
a.inject(:merge)
#=> {:a=>:b, :c=>:d}
这会在每次迭代中从两个合并中启动一个新哈希。为了避免这种情况,你可以使用破坏性的:merge!(或者:update,都是一样的):
a.inject(:merge!)
#=> {:a=>:b, :c=>:d}
【讨论】:
试试这个
a.inject({}){|acc, hash| acc.merge(hash)} #=> {:a=>:b, :c=>:d}
【讨论】:
随便用
a.reduce(:merge)
#=> {:a=>:b, :c=>:d}
【讨论】:
我遇到了这个答案,我想比较两个选项的性能,看看哪个更好:
a.reduce Hash.new, :mergea.inject(:merge)使用 ruby 基准测试模块,事实证明选项 (2) a.inject(:merge) 更快。
用于比较的代码:
require 'benchmark'
input = [{b: "c"}, {e: "f"}, {h: "i"}, {k: "l"}]
n = 50_000
Benchmark.bm do |benchmark|
benchmark.report("reduce") do
n.times do
input.reduce Hash.new, :merge
end
end
benchmark.report("inject") do
n.times do
input.inject(:merge)
end
end
end
结果
user system total real
reduce 0.125098 0.003690 0.128788 ( 0.129617)
inject 0.078262 0.001439 0.079701 ( 0.080383)
【讨论】:
reduce 和 inject 是别名。快速检查您的测试显示减速是由于 Hash.new 作为初始化程序。 :merge 每次迭代都会创建一个新的哈希值。 :update 没有。因此,使用:update 重新运行显示,即使使用Hash.new,:update 版本更快:``` 用户系统总实际减少 w/Hash.new & :update 0.056754 0.002097 0.058851 (0.059330) 减少w/ : 仅合并 0.090021 0.001081 0.091102 ( 0.091257)```
您可以将其转换为数组[[:a, :b]],然后将所有内容转换为哈希{:a=>:b}
# it works like [[:a, :b]].to_h => {:a=>:b}
[{a: :b}, {c: :d}].map { |hash| hash.to_a.flatten }.to_h
# => {:a=>:b, :c=>:d}
【讨论】: