J'ai un tableau de hachages:
[{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3>}, {"Dry Goods"=>2}]
Je dois utiliser inject
ici, je pense, mais j'ai vraiment du mal.
Je veux un nouveau hachage qui reflète la somme des clés en double du hachage précédent:
[{"Vegetable"=>15}, {"Dry Goods"=>5}]
Je contrôle le code qui génère ce hachage afin que je puisse le modifier si nécessaire. Les résultats étaient principalement des hachages car cela pourrait finir par imbriquer n'importe quel nombre de niveaux en profondeur et il est ensuite facile d'appeler aplatir sur le tableau, mais pas d'aplatir les clés/valeurs du hachage aussi:
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
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
avec un bloc exécute le bloc lorsqu'il trouve un doublon; inject
sans initiale memo
traite le premier élément du tableau comme memo
, ce qui est bien ici.
Utilisez simplement:
array = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3}, {"Dry Goods"=>2}]
array.inject{|a,b| a.merge(b){|_,x,y| x + y}}
ar = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3}, {"Dry Goods"=>2}]
Tandis que le Hash.merge
la technique fonctionne bien, je pense qu'elle se lit mieux avec un inject
:
ar.inject({}) { |memo, subhash| subhash.each { |prod, value| memo[prod] ||= 0 ; memo[prod] += value } ; memo }
=> {"Dry Goods"=>5, "Vegetable"=>15}
Mieux encore, si vous utilisez Hash.new
avec une valeur par défaut de 0:
ar.inject(Hash.new(0)) { |memo, subhash| subhash.each { |prod, value| memo[prod] += value } ; memo }
=> {"Dry Goods"=>5, "Vegetable"=>15}
Ou si inject
vous fait mal à la tête:
result = Hash.new(0)
ar.each { |subhash| subhash.each { |prod, value| result[prod] += value } }
result
=> {"Dry Goods"=>5, "Vegetable"=>15}
Si vous disposez de deux hachages avec plusieurs clés:
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
Je ne suis pas sûr qu'un hachage soit ce que vous voulez ici, car je n'ai pas plusieurs entrées dans chaque hachage. je vais donc commencer par changer un peu la représentation de vos données.
ProductCount=Struct.new(:name,:count)
data = [ProductCount.new("Vegetable",10),
ProductCount.new("Vegetable",5),
ProductCount.new("Dry Goods",3),
ProductCount.new("Dry Goods",2)]
Si les hachages peuvent avoir plusieurs paires clé-valeur, alors ce que vous voulez probablement faire est
data = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3>}, {"Dry Goods"=>2}]
data = data.map{|h| h.map{|k,v| ProductCount.new(k,v)}}.flatten
Utilisez maintenant la gemme à facettes comme suit
require 'facets'
data.group_by(&:name).update_values{|x| x.map(&:count).sum}
Le résultat est
{"Dry Goods"=>5, "Vegetable"=>15}