2012-06-08 15 views
5

dire che ho un hash come:Ordina hash per anzianità di valori contenuti

foo = { 
    :bar => ['r', 'baz'], # has a total str length of 4 characters inside of the array 
    :baz => ['words', 'etc', 'long words'] # has a total str length of 18 characters inside of the array, 
    :blah => ['at'] # has a total str length of 2 characters inside of the array 
    # etc... 
} 

Come posso fare per l'ordinamento questo hash per la lunghezza totale della stringa degli elementi contenuti all'interno delle matrici? L'ordine di hash risultante in questo caso dovrebbe essere: :blah, :bar, :baz

+1

Cosa intendi con "ordinamento hash"? – nonowarn

+2

Immagina per un secondo Ruby non può aiutarti. Cosa faresti allora? – alf

+0

@alf Immagino che sarei SOL ... ma come posso dirmelo? –

risposta

11

avevo appena fare questo:

Hash[foo.sort_by { |k, v| v.join.length }] 

Presumo che non stai intendendo il cambiamento dei valori hash originali, appena ri-ordine di loro.

1
foo.sort_by { |_,v| v.reduce(:+).size } 
+0

Anche 'ridurre (: +)' è sufficiente. Tuttavia questo ordina per stringa (in ordine alfabetico), non per lunghezza della stringa. – Casper

+0

@Casper hai ragione. Ho modificato la risposta per utilizzare la lunghezza della stringa. –

3

Tradizionalmente, gli hash non sono ordinate, e quindi non ordinabile. Gli hash di Ruby 1.9 sono ordinati, ma il linguaggio non offre un modo semplice per riordinare gli elementi. Proprio come in 1.8, l'ordinamento di un hash restituisce un array di coppie: (. In realtà, 1.8 sarebbe saltare in aria su questo perché i simboli non sono paragonabili a 1.8, ma non importa)

{ c:3, a:1, b:2 }.sort => [ [:a,1], [:b,2], [:c,3] ] 

Ma, come Finché sei d'accordo con l'elenco di coppie, puoi ordinare un hash (o un array) da qualsiasi cosa tu voglia. Basta usare sort_by e superare un blocco che estrae la chiave di ordinamento, o utilizzare sorta con un blocco che fa il confronto:

foo.sort_by { |key, strings| strings.join.length } 

o, se si desidera che le più lunghe prima:

foo.sort_by { |key, strings| -strings.join.length } 

Poi, se si sta utilizzando 1.9 e vuole trasformare il risultato di nuovo in un hash, è possibile farlo in tal modo (grazie, Jörg W Mittag):

Hash[ foo.sort_by { |key, strings| strings.join.length } ] 

... che è la stessa risposta d11wtq.

+0

'Hash :: []' prende esattamente il tipo di matrici di valori-chiave che producono tutti gli altri metodi 'Hash', quindi, se vuoi' map' o 'sort' o' sort_by' a 'Hash', tu avvolgere l'intera espressione in "Hash [...]" per ottenere un 'Hash'. –

1

Hash non garantisce l'ordine delle chiavi nel suo concetto. Ma in Ruby 1.9, Hash's key order is saved. Quindi puoi usare il codice in altre risposte se usi 1.9.

Ma non voglio raccomandare di fare affidamento su questo comportamento perché è un comportamento implicito e ho paura dei cambiamenti futuri. Invece, usa il metodo restituendo la voce hash in ordine di somma della lunghezza delle stringhe.

def each_by_length(hash) 
    hash = hash.sort_by { |_, strs| strs.map(&:length).inject(0, &:+) } 
    hash.each do |k, v| 
    yield k, v 
    end 
end 
Problemi correlati