2011-10-06 13 views
16

tengo una matriz, que se emite por un map/reduce método realizado por MongoDB, se ve algo como esto:grupo Rubí hashes por valor de clave

[{"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}] 

Se dará cuenta de que hay tres distintos valores para type, en este caso 0, 1 y 2, ahora quieren hacer es agrupar esta gama de valores hash por el valor de su clave type, así que por ejemplo esta matriz terminaría a buscar 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é estas matrices ejemplo, son muy grandes, pero creo que puede ser un problema más sencillo de lo que estoy haciendo que fuera a ser

Así que, básicamente, cada matriz de valores hash se agrupa por el valor de su type clave, y luego regresó como un hash con una matriz para cada tipo, cualquier ayuda sería realmente muy útil, incluso algunos consejos útiles serían muy apreciados.

+0

posible duplicado de [Mejor manera de dividir las matrices en múltiples matrices pequeñas en Ruby] (http://stackoverflow.com/questions/5686493/best-way-to-split-arrays -in-multiple-small-arrays-in-ruby) – akostadinov

Respuesta

30
array.group_by {|x| x['type']} 

o si desea que las cosas claves símbolo Incluso se puede

array.group_by {|x| "type_#{x['type']}".to_sym} 

creo esto lo expresa mejor "Así que, básicamente, cada matriz de hash sería agrupados por el valor de su clave de tipo, y luego devuelto como un hash con una matriz para cada tipo ", incluso si deja la clave :type sola en los valores hash de salida.

+2

no produce el resultado en la pregunta, y no funciona en Ruby 1.8 –

+2

Esto agrupará, pero no borrará el 'tipo' en la respuesta. No me importa eso, ya que es simple, pero no responde la pregunta, tbh. – pjammer

2
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: ligeramente diferentes claves hash aquí, he utilizado los valores de tipo directamente como la clave

si usted tiene que tener las llaves de hash como en tu ejemplo, puede agregar la línea que se comenta fuera.


P.S .: ¡Acabo de ver la solución de Tapio, es muy bonita y corta! Tenga en cuenta que solo funciona con Ruby> = 1.9

+1

¿por qué no simplemente 'a.group_by {| x | x ['type']} '? –

+0

¿En eso no elimina la tecla 'tipo'? No creo que eso realmente importe, ¿verdad? –

+0

@Tapio: en su ejemplo, esperaba que la clave "tipo" se elimine de los hashes en el camino ... Sí, estoy de acuerdo, en realidad no importa ... group_by() es nuevo y delicioso, ¡gracias! +1 – Tilo

2

¿Algo así como esto?

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 se preocupan por preservar 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 
0

group_byrecoge un enumerable en conjuntos, agrupados por el resultado de un bloque. Usted no está obligado a conseguir simplemente el valor de la clave en este bloque, por lo que si desea omitir la 'type' en esos juegos en que puede hacerlo, como en:

array.group_by {|x| "type_#{x.delete('type').to_i}".to_sym} 

Esto dará lugar exactamente en lo que has pedido.

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 va a hacer el truco:

array.map(&:dup).group_by {|x| "type_#{x.delete('type').to_i}".to_sym} 
Cuestiones relacionadas