【问题标题】:How to sum all deeply nested values in a hash如何对哈希中的所有深层嵌套值求和
【发布时间】:2015-01-16 07:32:20
【问题描述】:

我有一个像这样的哈希:

hash = {"0"=>{"0"=>"148", "1"=>"2", "2"=>"90", ....}, "1"=>{"0"=>10}, .....}

我想添加所有深层嵌套的值。对所有值求和的最佳和最优方法是什么?

我试过这样做:

hash.values.inject(0){|m,n| m + n.values.map(&:to_i).sum}

【问题讨论】:

  • 您的哈希值是否保证只有 2 的深度?

标签: ruby hash sum


【解决方案1】:

求解任意深度与求解固定深度没有太大区别:递归的直接应用。如果当前值是一个哈希值,则将其相加并将其添加到总数中,如果不是则添加值本身。

def hash_sum(h)
  h.values.inject(0) do |total, value|
    case value
    when Hash then total + hash_sum(value)
    else
      total + value.to_i
    end
  end
end

【讨论】:

    【解决方案2】:

    根据 cmets 和示例,我假设所有相关值都恰好位于深度 2。

    hash = {"0"=>{"0"=>"148", "1"=>"2", "2"=>"90"}, "1"=>{"0"=>10}}
    hash.values.flat_map(&:values).map(&:to_i).inject(:+)
    # => 250
    

    如果您在深度 3 处拥有所有值,则添加另一个 flat_map(&:values)

    hash = {"3" => {"0"=>{"0"=>"148", "1"=>"2", "2"=>"90"}, "1"=>{"0"=>10}}, "4" => {"0"=> {"1" => "6"}}}
    hash.values.flat_map(&:values).flat_map(&:values).map(&:to_i).inject(:+)
    # => 256
    

    【讨论】:

      【解决方案3】:

      这是一个递归方法,它是 Frederick 的变体:

      def deep_hash(obj)
        return obj.to_i unless obj.is_a? Hash
        obj.reduce(0) { |t,(_,v)| t + deep_hash(v) }
      end
      
      hash = { "0"=>{ "0"=>"148, "1"=>"2", "2"=>"90" },
               "1"=>{ "0"=>10, "1"=>{ "0"=>16 } } }
      
      deep_hash(hash)
        #=> 266
      

      【讨论】:

        【解决方案4】:

        对于最多两层嵌套(源自您的解决方案):

        hash = {"0"=>{"0"=>"148", "1"=>"2", "2"=>"90"}, "1"=>{"0"=>10}}
        hash.values.inject(0) { |m, n| 
          Hash === n ? m + n.values.map(&:to_i).reduce(&:+) : m + n.to_i 
        }
        #⇒ 250
        

        无限嵌套解决方案:

        def sum_deeply(h)
          h.values.inject(0) { |m, v| 
            m + (Hash === v ? sum_deeply(v) : v.to_i) 
          } 
        end
        sum_deeply(hash)
        #⇒ 250
        

        希望对你有帮助。

        【讨论】:

        • 不一致。 injectreduce 是彼此的别名。为什么要同时使用?
        • @sawa 与两个别名存在的原因相同。第一个操作实际上是injecting,而后者是reducing。我敢肯定,这是非常一致的,在这种情况下我会拒绝更改命名。
        • 只是为了澄清一下:第二个sn-p中有reduce,这显然是错误的,我改变了它。第一个 sn-p 中的 reduceinject 都是故意存在的。
        猜你喜欢
        • 1970-01-01
        • 2021-04-28
        • 1970-01-01
        • 2016-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-23
        • 2022-12-11
        相关资源
        最近更新 更多