que - Hashes de grupo Ruby por valor de clave
ruby create hash (4)
Tengo una matriz, que sale por un método map / reduce realizado por MongoDB, se ve más o menos así:
[{"minute"=>30.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>0.0, "count"=>299.0},
{"minute"=>30.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>10.0, "count"=>244.0},
{"minute"=>30.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>1.0, "count"=>204.0},
{"minute"=>45.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>0.0, "count"=>510.0},
{"minute"=>45.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>10.0, "count"=>437.0},
{"minute"=>0.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>0.0, "count"=>469.0},
{"minute"=>0.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>10.0, "count"=>477.0},
{"minute"=>15.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>0.0, "count"=>481.0},
{"minute"=>15.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>10.0, "count"=>401.0},
{"minute"=>30.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>0.0, "count"=>468.0},
{"minute"=>30.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>10.0, "count"=>448.0},
{"minute"=>45.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>0.0, "count"=>485.0},
{"minute"=>45.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>10.0, "count"=>518.0}]
Notarás que hay tres valores distintos para el type
, en este caso 0
, 1
y 2
, que ahora quiero hacer es agrupar esta matriz de valores hash por el valor de su type
clave, por ejemplo, esta matriz terminaría luciendo como :
{
:type_0 => [
{"minute"=>30.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>299.0},
{"minute"=>45.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>510.0},
{"minute"=>0.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>469.0},
{"minute"=>15.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>481.0},
{"minute"=>30.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>468.0},
{"minute"=>45.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>485.0}
],
:type_1 => [
{"minute"=>30.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>204.0}
],
:type_10 => [
{"minute"=>30.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>244.0},
{"minute"=>45.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>437.0},
{"minute"=>0.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>477.0},
{"minute"=>15.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>401.0},
{"minute"=>30.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>448.0},
{"minute"=>45.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>518.0}
]
}
así que sé que estas matrices de ejemplo son realmente grandes, pero creo que puede ser un problema más simple de lo que estoy imaginando
Así que, básicamente, cada matriz de hashes se agruparía por el valor de su clave de type
, y luego se devolvería como un hash con una matriz para cada tipo, cualquier ayuda sería realmente útil, incluso algunos consejos útiles serían muy apreciados.
Algo como esto tal vez?
mangled = a.group_by { |h| h[''type''].to_i }.each_with_object({ }) do |(k,v), memo|
tk = (''type_'' + k.to_s).to_sym
memo[tk] = v.map { |h| h = h.dup; h.delete(''type''); h }
end
O si no te importa conservar los datos originales:
mangled = a.group_by { |h| h[''type''].to_i }.each_with_object({ }) do |(k,v), memo|
tk = (''type_'' + k.to_s).to_sym
memo[tk] = v.map { |h| h.delete(''type''); h } # Drop the h.dup in here
end
group_by
recoge un enumerable en conjuntos, agrupados por el resultado de un bloque . No está obligado a obtener simplemente el valor de la clave en este bloque, por lo que si desea omitir el ''type''
en esos conjuntos, puede hacerlo, como en:
array.group_by {|x| "type_#{x.delete(''type'').to_i}".to_sym}
Esto dará como resultado exactamente lo que pediste.
Avanzado: Esto va un poco fuera del alcance de la pregunta, pero si desea conservar la matriz original, debe duplicar cada objeto dentro de ella. Esto hará el truco:
array.map(&:dup).group_by {|x| "type_#{x.delete(''type'').to_i}".to_sym}
array.group_by {|x| x[''type'']}
o si quiere las cosas clave de símbolo que podría incluso
array.group_by {|x| "type_#{x[''type'']}".to_sym}
Creo que esto expresa mejor "Así que, básicamente, cada matriz de hashes se agruparía por el valor de su clave de tipo , y luego se devolvería como un hash con una matriz para cada tipo ", incluso si deja la tecla :type
sola en los hash de salida .
by_type = {}
a.each do |h|
type = h.delete("type").to_s
# type = ("type_" + type ).to_sym
by_type[ type ] ||= []
by_type[ type ] << h # note: h is modified, without "type" key
end
Nota: teclas hash ligeramente diferentes aquí, utilicé los valores de tipo directamente como la clave
si debe tener las teclas hash como en su ejemplo, puede agregar la línea que está comentada.
PD: ¡Acabo de ver la solución de Tapio, es muy bonita y corta! Tenga en cuenta que solo funciona con Ruby> = 1.9