【问题标题】:Array of hashes to hash要散列的散列数组
【发布时间】:2012-06-12 05:19:04
【问题描述】:

例如,我有单个哈希数组

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

将它转换成这个的最好方法是什么?

{a: :b, c: :d}

【问题讨论】:

    标签: ruby arrays hash


    【解决方案1】:

    你可以使用

    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)
    • @tokland,将您的评论作为单独的答案发表 - 它应该会获得更多可见性
    • 如果您的应用程序允许,tokland 建议的:update 版本是更快的选择。
    【解决方案2】:

    这两个:

    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
    

    【讨论】:

      【解决方案3】:

      你可以使用.inject:

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

      Demonstration

      这会在每次迭代中从两个合并中启动一个新哈希。为了避免这种情况,你可以使用破坏性的:merge!(或者:update,都是一样的):

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

      Demonstration

      【讨论】:

      • 那是疯狂的优雅。谢谢。
      【解决方案4】:

      试试这个

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

      【讨论】:

        【解决方案5】:

        随便用

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

        【讨论】:

          【解决方案6】:

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

          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)
          

          【讨论】:

          • 这个结果让我很困惑。 docsreduceinject 是别名。快速检查您的测试显示减速是由于 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)```
          【解决方案7】:

          您可以将其转换为数组[[: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}
          

          【讨论】:

            猜你喜欢
            • 2012-08-03
            • 2014-05-19
            • 2015-04-21
            • 2010-12-04
            • 2018-06-29
            • 1970-01-01
            • 2011-03-13
            • 2011-10-09
            • 2021-08-22
            相关资源
            最近更新 更多