2009-06-11 17 views
11

Ho il seguente hash:Ordinamento hash di hash per valore (e restituire il hash, non un array)

user = { 
    'user' => { 
    'title' => {'weight' => 1, .... } 
    'body' => {'weight' => 4, ....} 
    .... 
    .... 
    } 
} 

IS è possibile ottenere l'utente allineati secondo la chiave peso delle sue hash bambino?

Ho cercato su Hash.sort, ma sembra che restituisca array piuttosto che il mio hash originale ordinato.

risposta

11

In Ruby 1.9, Hash ES sono ordinati, ma Hash#sort restituisce ancora una Array di Array s. Immaginalo! Ciò implica che è possibile creare il proprio metodo di ordinamento su di esso.

class Hash 
    def sorted_hash(&block) 
    self.class[sort(&block)] # Hash[ [[key1, value1], [key2, value2]] ] 
    end 
end 

Hash es sono non ordinati in Ruby 1.8. Se si desidera la compatibilità con Ruby 1.8, è possibile utilizzare lo OrderedHash di ActiveSupport. Si comporta come un 1,9- Hash, in modo da poter definire lo stesso metodo sorted_hash su di esso:

class ActiveSupport::OrderedHash 
    def sorted_hash(&block) 
    self.class[sort(&block)] 
    end 
end 

hash = ActiveSupport::OrderedHash.new 
hash["b"] = "b" 
hash["a"] = "a" 
hash    #=> {"b"=>"b", "a"=>"a"} => unsorted 
hash.sorted_hash #=> {"a"=>"a", "b"=>"b"} => sorted! 

È necessario copiare il metodo sorted_hash al codice, perché non esiste per impostazione predefinita!

Aggiornamento per profonda ordinamento: Se stai cercando di ordinare qualcosa altro che il tasto cancelletto, passare un blocco al metodo sorted_hash (supponendo che l'attuazione dall'alto) come segue:

hash = ActiveSupport::OrderedHash.new 
hash["a"] = { "attr" => "2", "..." => "..." } 
hash["b"] = { "attr" => "1", "..." => "..." } 

# Unsorted. 
hash 
    #=> {"a"=>{"attr"=>"2", "..."=>"..."}, "b"=>{"attr"=>"1", "..."=>"..."}} 

# Sort on the "attr" key. (Assuming every value is a Hash itself!) 
hash.sorted_hash { |a, b| a[1]["attr"] <=> b[1]["attr"] } 
    #=> {"b"=>{"attr"=>"1", "..."=>"..."}, "a"=>{"attr"=>"2", "..."=>"..."}} 
+0

Non ti ho preso. Ho cercato nel codice sorgente OrderedHash dei binari 2.3.2 e non vedo nulla riguardo ai metodi di ordinamento. – Dharam

+0

@satynos: l'ho chiarito un po ', si spera. È necessario definire sorted_hash da soli, ma è davvero facile! Copia la mia implementazione, se vuoi. – molf

+0

@molf: eccellente ... grazie per il feedback e l'aiuto per l'implementazione. Inoltre, se implemento il tuo metodo in classe Hash, funzionerà? o dovrebbe essere implementato in ActiveSupport :: OrderedHash? – Dharam

8

Gli hash sono strutture di dati fondamentalmente non ordinate; Hash#sort è, infatti, quello che vuoi. Oppure, o ordina un elenco di chiavi e poi usalo per enumerare quando è il momento di emettere l'hash, invece di enumerare direttamente l'hash usando i propri metodi.

+3

Tecnicamente, gli Hash sono ordinati in Ruby 1.9. Ma penso che sia ancora generalmente meglio trattarli come se non lo fossero, dal momento che il supporto per il riordino e così non esiste. – Chuck

+0

Jim, puoi darmi un esempio? – Dharam

+0

"Tecnicamente, gli hash sono ordinati in Ruby 1.9" ... questo mi rende molto triste. Un hash non dovrebbe avere alcun ordine implicito! Certo, capisco volendo ordinare a volte ... ma creare un nome diverso per quella struttura dati! Grr. – Beska

Problemi correlati