2014-12-09 13 views
12

Sto cercando di ordinare un hash in ordine alfabetico per chiave, ma non riesco a trovare un modo per farlo senza creare la mia classe di ordinamento. Ho trovato il codice qui sotto per ordinare in base al valore se si tratta di un numero intero e sto cercando di modificarlo ma senza avere fortuna.Come ordinare un Ruby Hash in ordine alfabetico con i tasti

temp["ninjas"]=36 
temp["pirates"]=12 
temp["cheese"]=222 
temp.sort_by { |key, val| key } 

Il mio obiettivo è ordinare l'hash per tasto, quindi emettere i valori. Dovrò farlo più volte con diversi ordini hash ma con gli stessi valori.

+1

Il codice sembra di fare ciò che avete richiesto. Vuoi modificare la domanda per includere l'output che ti aspetti? –

+0

Ho assunto il presupposto che vuoi che il tuo output sia un altro hash. Sarebbe bello vederlo nella domanda in tal caso (quindi la domanda e la risposta corrisponderebbero). –

+1

Cosa vuoi come output? Gli hash non sono realmente ordinati (sono, per ordine di inserimento, a partire da Ruby 1.9+). Cosa stai cercando di fare in particolare? –

risposta

21

Supponendo che si desideri che l'output sia un hash che eseguirà l'iterazione dei tasti in ordine ordinato, quindi ci si trova quasi arrivati. Hash#sort_by restituisce un Array di Array s e gli array interni sono tutti e due gli elementi.

Ruby's Hash ha un costruttore che può consumare questa uscita.

Prova questo:

temp = Hash[ temp.sort_by { |key, val| key } ] 

Se il vostro hash ha mescolato tipi di chiave, questo non funzionerà (di Ruby non sarà automaticamente sorta tra String s e Symbol s per esempio) e si otterrà un messaggio di errore come confronto di Symbol with String failed (ArgumentError). In tal caso, è possibile modificare quanto sopra a

temp = Hash[ temp.sort_by { |key, val| key.to_s } ] 

per risolvere il problema. Tuttavia, tieni presente che le chiavi manterranno comunque i loro tipi originali che potrebbero causare problemi con ipotesi nel codice successivo. Inoltre, la maggior parte delle classi incorporate supporta un metodo .to_s, pertanto è possibile ottenere risultati indesiderati (ad esempio un ordinamento imprevisto per chiavi numeriche o altri tipi imprevisti).

Si potrebbe, oltre, convertire le chiavi per Strings con qualcosa di simile:

temp = Hash[ temp.map { |key, val| [key.to_s, val] }.sort ] 

. . . sebbene questo approccio perderebbe informazioni sul tipo della chiave originale rendendo impossibile ricondurre i dati originali in modo affidabile.

+0

Ho provato il tuo codice ma ho ottenuto: in 'sort_by': confronto di Symbol with String failed (ArgumentError) – Rilcon42

+0

Il tuo hash ha tipi di chiave mista e avrai questo problema, tuttavia, vuoi ordinarli. Potresti modificarlo in 'temp = Hash [temp.sort_by {| key, val | key.to_s}] 'per aggirare il problema, ma attenzione, questo cambierà i tasti Symbol in Stringhe. . . se vuoi veramente lavorare con i dati in ordine, devi decidere di un tipo di dati per le tue chiavi e mantenerlo con esso –

+0

ti dispiacerebbe aggiornare la tua risposta per prendere nota di come risolvere il problema per i futuri utenti che potrebbe non leggere i commenti? Grazie! – Rilcon42

4

Ruby's Hash ricorda l'ordine di inserimento ora, ma i precedenti Rubini < v1.9 no. Ma non preoccuparti di ordinare un hash perché non c'è alcun vantaggio nel farlo perché fondamentalmente un hash è una struttura ad accesso casuale. Ciò significa che gli elementi sono tutti accessibili in qualsiasi momento e non farà differenza se uno è il primo o l'ultimo, puoi accedervi allo stesso modo.

Ecco a differenza di un array che agisce come un file sequenziale/di testo o una catena o una coda e si deve accedere in modo lineare mediante iterazione su di essa, che, a quel punto, l'ordine degli elementi fa una grande differenza.

Quindi, con un hash, ottenere le chiavi, ordinarle e scorrere l'elenco delle chiavi o utilizzare values_at per recuperare tutti i valori contemporaneamente. Per esempio:

hash = { 
    'z' => 9, 
    'a' => 1 
} 

sorted_keys = hash.keys.sort # => ["a", "z"] 
sorted_keys.each do |k| 
    puts hash[k] 
end 
# >> 1 
# >> 9 

hash.values_at(*sorted_keys) # => [1, 9] 

Alcune lingue non sarà nemmeno permettono di ordinare l'hash, e l'accesso tramite un elenco ordinato di chiavi è l'unico modo per estrarre gli elementi di un ordine, quindi è probabilmente una buona idea non prendere l'abitudine di affidarsi all'ordine delle coppie chiave/valore, e invece affidarsi alle chiavi.

+1

La tua affermazione che l'ordinamento di un hash "non ha alcun vantaggio" è vero solo nel caso di ricerca. Se vuoi sapere * riguardo * l'hash. (ad esempio, creando un md5 dei contenuti dell'hash), un ordine coerente è pertinente e necessario. – MissingHandle

+0

Poiché la domanda riguarda specificamente le ricerche, il tuo commento ha poca rilevanza. Sì, la creazione di un MD5 dell'intero oggetto è talvolta utile, ma poiché la maggior parte delle volte le persone recuperano i valori, l'ordinamento dell'hash non sarà di aiuto. –

+0

Stavo solo cercando di perfezionare l'affermazione che hai fatto "non preoccuparti di ordinare un hash perché non c'è alcun vantaggio" per tutti i noob là fuori che potrebbero usare la loro mente espansa mentre imparano :). Saluti! – MissingHandle

5
sorted_by_key = Hash[original_hash.sort] 

creerà un nuovo hash inserendo la chiave/valori original_hash alfabeticamente per chiave. Gli hash di Ruby 2.x ricordano il loro ordine di inserimento, quindi questo nuovo hash apparirà ordinato per chiave se lo si enumera o lo si stampa.

Se si inseriscono più elementi in un ordine non alfabetico, ciò non verrà mantenuto.

Inoltre, questo presuppone che le chiavi di hash originali siano tutte ordinabili/confrontabili.

0

È possibile creare un nuovo hash vuoto per contenere i dati hash ordinati. Scorrere l'array restituito e caricare i dati nel nuovo hash per conservare i dati hash ordinati.

temp = {} 
temp["ninjas"]=36 
temp["pirates"]=12 
temp["cheese"]=222 
temp = temp.sort_by { |key, val| key } 

temp_sorted = {} 
temp.each { |sub_arr| temp_sorted[sub_arr[0]] = sub_arr[1] } 
temp = temp_sorted 

temperatura ora è uguale a { "formaggio" => 222, "ninja" => 36, "pirati" => 12}

Problemi correlati