2009-06-11 3 views
11

Ich habe folgende hash:Sortierung Hash von Hashes nach Wert (und den Hash zurückgeben, kein Array)

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

Ist ist möglich, durch das Gewicht Schlüssel ihres Kindes Hashes der Nutzer sortiert zu erhalten?

Ich schaute in der Hash.sort, aber es sieht aus wie es Array zurückgibt, anstatt meine ursprünglichen Hash sortiert.

Antwort

11

In Ruby 1.9 sind Hash es sortiert, aber Hash#sort gibt noch eine Array von Array s. Stell dir das vor! Es bedeutet, dass Sie Ihre eigene Sortiermethode darüber hinaus erstellen können.

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

Hash Es sind unsortierte in Ruby 1.8. Wenn Sie Ruby 1.8-Kompatibilität möchten, können Sie ActiveSupport OrderedHash verwenden. Es verhält sich wie ein 1,9- Hash, so können Sie das gleiche sorted_hash Methode auf sie definieren:

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! 

Sie haben die sorted_hash Methode, um Ihren Code zu kopieren, weil es nicht standardmäßig vorhanden ist!

Update für tiefe Sortierung: Wenn Sie auf etwas anderes als der Hash-Schlüssel zu sortieren, suchen, um einen Block zu der sorted_hash Methode übergeben wie folgt (die Implementierung von oben unter der Annahme):

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

Ich habe dich nicht bekommen. Ich habe im OrderedHash Quellcode der Rails 2.3.2 nachgeschaut und sehe keine Sortiermethoden. – Dharam

+0

@satynos: Ich habe es hoffentlich ein wenig geklärt. Sie müssen sorted_hash selbst definieren, aber es ist wirklich einfach! Kopieren Sie einfach meine Implementierung, wenn Sie möchten. – molf

+0

@molf: Ausgezeichnet ... danke für das Feedback und Hilfe bei der Umsetzung. Auch wenn ich Ihre Methode in Hash-Klasse implementieren, wird es funktionieren? oder sollte es in ActiveSupport :: OrderedHash implementiert werden? – Dharam

8

Hashes sind grundsätzlich unsortierte Datenstrukturen; Hash#sort ist in der Tat, was Sie wollen. Entweder das, oder sortieren Sie eine Liste von Schlüsseln und verwenden Sie diese, um aufzuzählen, wenn es Zeit ist, den Hash auszugeben, anstatt direkt über den Hash mit seinen eigenen Methoden zu nummerieren.

+3

Technisch gesehen sind Hashes in Ruby 1.9 geordnet. Aber ich denke, es ist im Allgemeinen immer noch besser, sie so zu behandeln, als ob sie es nicht wären, da Unterstützung für Nachbestellungen und dergleichen nicht existiert. – Chuck

+0

Jim, kannst du mir ein Beispiel geben? – Dharam

+0

"Technisch gesehen sind Hashes in Ruby 1.9 geordnet" ... das macht mich sehr traurig. Ein Hash sollte keine implizite Reihenfolge haben! Klar, ich verstehe, dass ich manchmal bestellen muss ... aber erstelle einen anderen Namen für diese Datenstruktur! Gr. – Beska