example create array ruby hash key enumerable

ruby - create - Agrupe hashes por claves y suma los valores



key value ruby (5)

No estoy seguro de que un hash sea lo que quieras aquí, porque no tengo entradas múltiples en cada hash. entonces comenzaré cambiando un poco la representación de datos.

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 los valores hash pueden tener múltiples pares clave-valor, entonces lo que probablemente quiera hacer es

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

Ahora usa la gema de facetas de la siguiente manera

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

El resultado es

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

Tengo una variedad de hashes:

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

Necesito inject aquí, creo, pero realmente he estado luchando.

Quiero un nuevo hash que refleje la suma de las claves duplicadas del hash anterior:

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

Tengo el control del código que genera este hash para poder modificarlo si es necesario. Los resultados fueron principalmente hash, ya que esto podría terminar anidando cualquier cantidad de niveles de profundidad y luego es fácil invocar el aplanamiento en la matriz pero no aplanar las claves / valores del hash también:

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


Si tiene dos valores hash con varias claves:

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


Simplemente use:

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}]

Si bien la técnica Hash.merge funciona bien, creo que se lee mejor con una inject :

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

Mejor aún, si usa Hash.new con un valor predeterminado de 0:

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

O si la inject hace doler la cabeza:

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


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 con un bloque ejecuta el bloque cuando encuentra un duplicado; inject sin una memo inicial trata el primer elemento de la matriz como memo , lo cual está bien aquí.