Group hashes by keys and sum the values

前端 未结 5 2093
情话喂你
情话喂你 2020-11-27 03:50

I have an array of hashes:

[{\"Vegetable\"=>10}, {\"Vegetable\"=>5}, {\"Dry Goods\"=>3>}, {\"Dry Goods\"=>2}]

I need to use

相关标签:
5条回答
  • 2020-11-27 04:00

    If have two hashes with multiple keys:

    h1 = { "Vegetable" => 10, "Dry Goods" => 2 }
    h2 = { "Dry Goods" => 3, "Vegetable" => 5 }
    details = {}
    (h1.keys | h2.keys).each do |key|
      details[key] = h1[key].to_i + h2[key].to_i
    end
    details
    
    0 讨论(0)
  • 2020-11-27 04:09
    ar = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3}, {"Dry Goods"=>2}]
    

    While the Hash.merge technique works fine, I think it reads better with an inject:

    ar.inject({}) { |memo, subhash| subhash.each { |prod, value| memo[prod] ||= 0 ; memo[prod] += value } ; memo }
    => {"Dry Goods"=>5, "Vegetable"=>15}
    

    Better yet, if you use Hash.new with a default value of 0:

    ar.inject(Hash.new(0)) { |memo, subhash| subhash.each { |prod, value| memo[prod] += value } ; memo }
    => {"Dry Goods"=>5, "Vegetable"=>15}
    

    Or if inject makes your head hurt:

    result = Hash.new(0)
    ar.each { |subhash| subhash.each { |prod, value| result[prod] += value } }
    result
    => {"Dry Goods"=>5, "Vegetable"=>15}
    
    0 讨论(0)
  • 2020-11-27 04:12

    I'm not sure that a hash is what you want here, because I don't multiple entries in each hash. so I'll start by changing your data representation a little.

    ProductCount=Struct.new(:name,:count)
    data = [ProductCount.new("Vegetable",10),
            ProductCount.new("Vegetable",5),
            ProductCount.new("Dry Goods",3),
            ProductCount.new("Dry Goods",2)]
    

    If the hashes can have multiple key-value pairs, then what you probably want to do is

    data = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3>}, {"Dry Goods"=>2}]
    data = data.map{|h| h.map{|k,v| ProductCount.new(k,v)}}.flatten
    

    Now use the facets gem as follows

    require 'facets'
    data.group_by(&:name).update_values{|x| x.map(&:count).sum}
    

    The result is

    {"Dry Goods"=>5, "Vegetable"=>15}
    
    0 讨论(0)
  • 2020-11-27 04:18

    Simply use:

    array = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3}, {"Dry Goods"=>2}]
    array.inject{|a,b| a.merge(b){|_,x,y| x + y}}
    
    0 讨论(0)
  • 2020-11-27 04:19
    ar = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3}, {"Dry Goods"=>2}]
    p ar.inject{|memo, el| memo.merge( el ){|k, old_v, new_v| old_v + new_v}}
    #=> {"Vegetable"=>15, "Dry Goods"=>5}
    

    Hash.merge with a block runs the block when it finds a duplicate; inject without a initial memo treats the first element of the array as memo, which is fine here.

    0 讨论(0)
提交回复
热议问题