45

我有一个哈希数组:

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

我想我需要在inject这里使用,但我真的很挣扎。

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

[{"Vegetable"=>15}, {"Dry Goods"=>5}]

我控制着输出此哈希的代码,因此我可以在必要时对其进行修改。结果主要是散列,因为这最终可能会嵌套任意数量的深度,然后很容易在数组上调用 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 
4

5 回答 5

92
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.mergewith a block 在找到重复项时运行该块;inject如果没有初始memo值,则将数组的第一个元素视为memo,这在这里很好。

于 2010-12-15T18:53:52.557 回答
16

只需使用:

array = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3}, {"Dry Goods"=>2}]
array.inject{|a,b| a.merge(b){|_,x,y| x + y}}
于 2013-11-14T00:19:03.397 回答
12
ar = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3}, {"Dry Goods"=>2}]

虽然这项Hash.merge技术工作得很好,但我认为它读起来更好inject

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

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

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

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

result = Hash.new(0)
ar.each { |subhash| subhash.each { |prod, value| result[prod] += value } }
result
=> {"Dry Goods"=>5, "Vegetable"=>15}
于 2012-08-06T23:38:04.163 回答
4

我不确定哈希是你想要的,因为我在每个哈希中没有多个条目。所以我将从稍微改变你的数据表示开始。

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

如果哈希可以有多个键值对,那么您可能想要做的是

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

现在使用 facets gem 如下

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

结果是

{"Dry Goods"=>5, "Vegetable"=>15}
于 2010-12-15T18:45:07.920 回答
4

如果有两个带有多个键的哈希:

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
于 2012-04-19T16:19:36.170 回答