例如,我有一个由单个哈希组成的数组。
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}
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
我看到这个答案,想比较两个选项的性能,看哪一个更好:
a.reduce Hash.new, :merge
a.inject(:merge)
使用ruby benchmark模块,结果表明选项(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
版本也更快: user system total real
reduce w/ Hash.new & :update 0.056754 0.002097 0.058851 ( 0.059330)
reduce w/ :merge only 0.090021 0.001081 0.091102 ( 0.091257)
- Greg Tarsaa.reduce(:merge)
#=> {:a=>:b, :c=>:d}
试试这个
a.inject({}){|acc, hash| acc.merge(hash)} #=> {:a=>:b, :c=>:d}
[[: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}
Hash.new
,或者像朋友们喜欢称呼它的那样,{}
:-) 虽然我喜欢纯函数式的解决方案,但请注意merge
会在每次迭代中创建一个新的哈希;我们可以使用update
替代它(这不会破坏输入哈希表,这很重要):hs.reduce({}, :update)
。 - tokland:update
版本,这是更快的选项。 - Greg Tarsa