哈希散列数组


68

例如,我有单个哈希数组

a = [{a: :b}, {c: :d}]

将其转换为此的最佳方法是什么?

{a: :b, c: :d}

Answers:


118

您可以使用

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}

36
Hash.new,或者作为朋友喜欢给他打电话,{}:-)就像我喜欢纯功能解决方案一样,请注意,merge它将在每次迭代中创建一个新的哈希;我们可以update改用(它不会弄乱输入的哈希值,这很重要):hs.reduce({}, :update)
tokland 2012年

@tokland,将您的评论作为一个单独的答案发布-它应该具有更高的知名度
Jason

如果您的应用程序允许,:updatetokland建议的版本是更快的选择。
格雷格·塔尔萨

44

您可以使用.inject

a.inject(:merge)
#=> {:a=>:b, :c=>:d}

示范

这会在合并后的两次迭代中启动新的哈希。为避免这种情况,您可以使用破坏性的:merge!(或:update,相同):

a.inject(:merge!)
#=> {:a=>:b, :c=>:d}

示范


多数民众赞成在疯狂优雅。谢谢。
保罗·怀特海德

21

这两个:

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

1

我遇到了这个答案,我想从性能上比较这两个选项,以查看哪个更好:

  1. a.reduce Hash.new, :merge
  2. a.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)

这个结果使我感到困惑。该文档reduceinject的别名。带测试的快速检查显示速度下降是由于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)```
格雷格TARSA



0

您可以将其转换为数组[[: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}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.