按键分组并对值求和

bla*_*ula 40 ruby hash key enumerable

我有一系列哈希:

[{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3>}, {"Dry Goods"=>2}]
Run Code Online (Sandbox Code Playgroud)

我需要在inject这里使用,但我确实在苦苦挣扎.

我想要一个反映前一个哈希重复键总和的新哈希:

[{"Vegetable"=>15}, {"Dry Goods"=>5}]
Run Code Online (Sandbox Code Playgroud)

我控制输出此哈希的代码,以便我可以在必要时进行修改.结果主要是哈希,因为这可能会最终嵌套任意数量的级别,然后很容易在数组上调用flatten但不会平滑哈希的键/值:

def recipe_pl(parent_percentage=nil)
  ingredients.collect do |i|

    recipe_total = i.recipe.recipeable.total_cost 
    recipe_percentage = i.ingredient_cost / recipe_total

    if i.ingredientable.is_a?(Purchaseitem)
      if parent_percentage.nil?
        {i.ingredientable.plclass => recipe_percentage}
      else
        sub_percentage = recipe_percentage * parent_percentage
        {i.ingredientable.plclass => sub_percentage}
      end
    else
      i.ingredientable.recipe_pl(recipe_percentage)
    end
  end
end 
Run Code Online (Sandbox Code Playgroud)

ste*_*lag 84

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}
Run Code Online (Sandbox Code Playgroud)

Hash.merge当一个块发现重复时,就会运行该块; inject没有初始化memo处理数组的第一个元素memo,这在这里很好.

  • +1这是那些需要在Ruby书籍中出现的珠宝之一,但事实并非如此. (2认同)

小智 12

只需使用:

array = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3}, {"Dry Goods"=>2}]
array.inject{|a,b| a.merge(b){|_,x,y| x + y}}
Run Code Online (Sandbox Code Playgroud)


Hea*_*ead 8

ar = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3}, {"Dry Goods"=>2}]
Run Code Online (Sandbox Code Playgroud)

虽然这项Hash.merge技术运作良好,但我认为它的读数更好inject:

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

更好的是,如果使用Hash.new默认值0:

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

或者如果inject让你的头受伤:

result = Hash.new(0)
ar.each { |subhash| subhash.each { |prod, value| result[prod] += value } }
result
=> {"Dry Goods"=>5, "Vegetable"=>15}
Run Code Online (Sandbox Code Playgroud)

  • 名副其实的有价值建议的聚宝盆 (2认同)