散列数组转换为散列

76
例如,我有一个由单个哈希组成的数组。
a = [{a: :b}, {c: :d}]

如何最好地将它转换成这样?

{a: :b, c: :d}
7个回答

131

你可以使用

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}

42
Hash.new,或者像朋友们喜欢称呼它的那样,{} :-) 虽然我喜欢纯函数式的解决方案,但请注意 merge 会在每次迭代中创建一个新的哈希;我们可以使用 update 替代它(这不会破坏输入哈希表,这很重要):hs.reduce({}, :update) - tokland
@tokland,请将您的评论作为单独的回答发布,这样可以获得更多的关注。 - Jason
如果您的应用程序允许,tokland建议使用:update版本,这是更快的选项。 - Greg Tarsa

58
您可以使用.inject:
a.inject(:merge)
#=> {:a=>:b, :c=>:d}

演示

在每次迭代时,它会从两个合并的哈希中初始化一个新的哈希。为了避免这种情况,您可以使用破坏性的:merge!(或相同的:update):

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

演示


这太优雅了。谢谢。 - Paul Danelli

25
这两个代码片段是等效的(reduce和inject都是同一个方法):
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

5

我看到这个答案,想比较两个选项的性能,看哪一个更好:

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

2
这个结果让我感到困惑。文档reduceinject是别名。通过你的测试快速检查后发现,减速是由于初始化器中的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 Tarsa

2
最初的回答:只需使用。
a.reduce(:merge)
#=> {:a=>:b, :c=>:d}

0

试试这个

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

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}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接