tengo una matriz como
[ [358, 202102, 5], [358, 202112, 5], [358, 202102, 10], [311, 202103, 5], [311, 202101, 1], [311, 202101, 1], [311, 202115, 8], [311, 202101, 1], [311, 202101, 1] ]Necesito un hash como este:
{ 358 => { 202102 => 15, 202112 => 5 }, 311 => { 202103 => 5, 202101 => 4, 202115 => 8 } }El orden no importa. Solo se deben sumar los terceros valores de cada fila de la matriz.
Puede resolver esto usando Enumberable#each_with_object de la siguiente manera
a = [ [358, 202102, 5], [358, 202112, 5], [358, 202102, 10], [311, 202103, 5], [311, 202101, 1], [311, 202101, 1], [311, 202115, 8], [311, 202101, 1], [311, 202101, 1] ] a.each_with_object(Hash.new {|h,k| h[k] = Hash.new(0)}) do |(k1,k2,val), obj| obj[k1][k2] += val end # => {358=>{202102=>15, 202112=>5}, 311=>{202103=>5, 202101=>4, 202115=>8}} Lo que esto hace es iterar sobre el Array ( a ) con un objeto acumulador ( obj ).
Este objeto es un Hash con un proceso predeterminado donde cada vez que se agrega una nueva clave, su valor se asigna como un nuevo hash con un valor predeterminado de 0.
En los argumentos del bloque, deconstruimos el Array en 3 argumentos (k1,k2,val) por lo que en el primer paso se vería así:
k1 = 358 k2 = 202102 val = 5 obj[k1] #=> {358=> {}} obj[k1][k2] #=> {358 => {202102 => 0 }} obj[k1][k2] += val obj #=> {358 => {202102 => 5 }}Otra forma es usar los métodos Hash#update (¡también conocido como merge! ) y Hash#merge que emplean bloques para determinar los valores de las claves que están presentes en ambos hashes que se fusionan. Consulte los documentos para conocer las definiciones de las tres variables de bloque. He usado un guión bajo para las primeras variables de bloque (la clave común de los valores hash que se fusionan) para indicar que no se usa en el cálculo del bloque.
a = [ [358, 202102, 5], [358, 202112, 5], [358, 202102, 10], [311, 202103, 5], [311, 202101, 1], [311, 202101, 1], [311, 202115, 8], [311, 202101, 1], [311, 202101, 1] ] a.each_with_object({}) do |(x,y,n),h| h.update(x=>{y=>n}) do |_,old1,new1| old1.merge(new1) { |_,old2,new2| old2+new2 } end end #=> {358=>{202102=>15, 202112=>5}, 311=>{202103=>5, 202101=>4, 202115=>8}}Al principio, creo un hash de hash con el valor predeterminado 0. Después de eso, solo agrego los valores del hash de hash en función del último valor de la matriz.
aoa = [ [358, 202102, 5], [358, 202112, 5], [358, 202102, 10], [311, 202103, 5], [311, 202101, 1], [311, 202101, 1], [311, 202115, 8], [311, 202101, 1], [311, 202101, 1] ] hash = Hash.new { |h,k| h[k] = Hash.new(0) } aoa.each { |ary| hash[ary[0]][ary[1]] += ary[2]} pp hashproducción:
{358=>{202102=>15, 202112=>5}, 311=>{202103=>5, 202101=>4, 202115=>8}}