2011-10-06 14 views
16

ho un array, che è uscita da una mappa/ridurre metodo eseguito da MongoDB, sembra qualcosa di simile:gruppo Rubino hash per valore della chiave

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

noterete che ci sono tre distinti valori per type, in questo caso 0, 1, e 2, ora voglio fare è questo gruppo array di hash per il valore la sua chiave type, così per esempio questo array finirebbe fuori assomigliando:

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

quindi so questi esempi di array sono molto grandi, ma penso che potrebbe essere un più semplice problema di quello che sto facendo fuori per essere

Quindi, in pratica ogni array di hash sarebbe raggruppato per il valore della sua type chiave, e poi restituito come un hash con una matrice per ogni tipo, qualsiasi aiuto sarebbe davvero molto utile, anche solo alcuni suggerimenti utili sarebbero molto apprezzati.

+0

possibile duplicato del [Il modo migliore per dividere gli array in più piccoli array in Ruby] (http://stackoverflow.com/questions/5686493/best-way-to-split-arrays -into-multiple-small-array-in-ruby) – akostadinov

risposta

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

o se si desidera che le cose fondamentali simbolo si potrebbe anche

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

penso questo esprime al meglio "Quindi in pratica ogni array di hash sarebbe raggruppato per il valore del suo tipo chiave e quindi restituito come hash con un array per ciascun tipo ", anche se lascia la chiave :type da solo negli hash di output.

+2

non produce l'output nella domanda e non funziona in Ruby 1.8 –

+2

Questo gruppo, ma non elimina il 'tipo' nella risposta. Non mi dispiace, perché è semplice, ma non risponde alla domanda, 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: leggermente diverse chiavi di hash qui, ho usato i valori di tipo direttamente come chiave

se si deve avere le chiavi di hash come nel tuo esempio, è possibile aggiungere la riga che è commentato su.


P.S .: Ho appena visto la soluzione di Tapio - è molto bello e breve! Si noti che funziona solo con Ruby> = 1.9

+1

perché non solo 'a.group_by {| x | x ['type']} '? –

+0

In quanto non rimuove la chiave "tipo"? Non penso che sarebbe davvero importante, vero? –

+0

@Tapio: nel suo esempio, si aspettava che la chiave "tipo" fosse rimossa dagli hash lungo la strada ... Sì, sono d'accordo, non importa ... group_by() è nuovo e buonissimo, grazie! +1 – Tilo

2

Qualcosa di simile forse?

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 se non si preoccupano di conservare i dati originari:

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_byraccoglie una enumerabile in serie, raggruppata in base al risultato di un blocco. Non siete costretti ad ottenere semplicemente il valore della chiave in questo blocco, quindi se si desidera omettere il 'type' in quei set si può fare, come in:

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

Ciò comporterà esattamente in quello che hai chiesto.

Avanzate: Questo va un po 'fuori dal campo di applicazione della domanda, ma se si desidera conservare l'array originale, è necessario duplicare ogni oggetto al suo interno.Ciò farà il trucco:

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