Ich bin mir nicht sicher, ob das Sortieren eines Hashs von großem Vorteil ist, es sei denn, Sie verwenden eachoder each_pairiterieren darüber. Selbst dann würde ich wahrscheinlich immer noch die Schlüssel greifen, diese sortieren und dann darüber iterieren und die Werte nach Bedarf abrufen. Dadurch wird sichergestellt, dass sich der Code auf älteren Rubinen korrekt verhält.
der Blechmann
Sinnvoll auch in Ruby 1.9. Ich hatte eine Sammlung von Terminen, gruppiert nach Datumsangaben (als Schlüssel), die von db kamen, und ich sortierte manuell nach Ruby. Z.B. {"2012-09-22": [...], "2012-09-30": [...], "2012-10-12": [...]}
Adit Saxena
Ja, ich finde Ihren Hash [h.sort] -Prozess effektiver als das Sortieren von Schlüsseln und den erneuten Zugriff auf den Hash über die sortierten Schlüssel.
@ Zachaysan, aber es funktioniert: h.sort{|a,z|a<=>z}.to_h(getestet 2.1.10, 2.3.3)
Whitehat101
@ whitehat101 Du hast recht. Ich hatte einen Fehler ( aist ein Array, nicht nur der Schlüssel). Ich habe meinen Kommentar gelöscht.
Zachaysan
Nur für den Fall, dass jemand anderes nach einer Möglichkeit sucht, ein Array von Hashes zu sortieren, reicht dies aus (wobei h das Array ist) : h.map(&:sort).map(&:to_h).
JM Janzen
82
Hinweis: Ruby> = 1.9.2 hat einen auftragserhaltenden Hash: Die eingefügten Auftragsschlüssel entsprechen der Reihenfolge, in der sie aufgelistet sind. Das Folgende gilt für ältere Versionen oder für abwärtskompatiblen Code.
Es gibt kein Konzept für einen sortierten Hash. Also nein, was du tust, ist nicht richtig.
Wenn Sie möchten, dass es zur Anzeige sortiert wird, geben Sie eine Zeichenfolge zurück:
oder, wenn Sie die Schlüssel in der richtigen Reihenfolge haben möchten:
h.keys.sort
oder, wenn Sie der Reihe nach auf die Elemente zugreifen möchten:
h.sort.map do|key,value|# keys will arrive in order to this block, with their associated value.end
Zusammenfassend macht es jedoch keinen Sinn, über einen sortierten Hash zu sprechen. In den Dokumenten heißt es: "Die Reihenfolge, in der Sie einen Hash nach Schlüssel oder Wert durchlaufen, scheint willkürlich zu sein und liegt im Allgemeinen nicht in der Einfügereihenfolge." Das Einfügen von Schlüsseln in einer bestimmten Reihenfolge in den Hash hilft also nicht.
"Ab 1.9.2 wird die Reihenfolge der Hash-Einfügungen beibehalten.", Und es ist süß.
der Blechmann
2
Zu meinem ersten Kommentar (der sich lustig anfühlt): Wenn Sie sich beispielsweise auf die Hash-Reihenfolge verlassen, wird dies für Ruby-Versionen, die älter als 1.9.2 sind, lautlos und unvorhersehbar unterbrochen.
Jo Liss
5
Wie kam diese Antwort zu ungefähr 20 + 1, ohne auch nur einen der beiden Teile der OP-Frage zu beantworten? "1) Wäre das (OP-Beispiel) der beste Weg, um einen Hash zu sortieren, 2) und ein Hash-Objekt zurückzugeben"? Ich beneide nicht um +1 :) Kurz nachdem ich die Antwort gelesen habe, bleiben mir immer noch die ursprünglichen Fragen. Auch wenn der Punkt ist, dass es keinen sortierten Hash gibt, schauen Sie sich die Kommentare für die ausgewählte Antwort auf diese Frage an. Stackoverflow.com/questions/489139/…
jj_
64
Ich habe immer benutzt sort_by. Sie müssen die #sort_byAusgabe umschließen Hash[], damit sie einen Hash ausgibt, andernfalls wird ein Array von Arrays ausgegeben. Um dies zu erreichen, können Sie alternativ die #to_hMethode für das Array von Tupeln ausführen , um sie in eine k=>vStruktur (Hash) zu konvertieren .
Wenn Sie sort_byeinen Hash verwenden, wird ein Array zurückgegeben. Sie müssten es erneut als Hash zuordnen. Hash[hsh.sort_by{|k,v| v}]
Stevenspiel
1
Ja, die Enumerator-Klasse interpretiert Hashes als Arrays, denke ich
boulder_ruby
3
Richtig, sortieren ist nach Werten : hsh.sort_by(&:last).to_h => {"b"=>10, "a"=>1000, "c"=>200000}.
Cary Swoveland
1
Beachten Sie, dass das Aufrufen to_hnur in Ruby 2.1.0+
Phrogz
1
Es gibt einen Tippfehler im Kommentar, Korrektur:sort_by{|k,v| v}.to_h)
Jitter
13
Nein, ist es nicht (Ruby 1.9.x)
require 'benchmark'
h ={"a"=>1,"c"=>3,"b"=>2,"d"=>4}
many =100_000
Benchmark.bm do|b|
GC.start
b.report("hash sort")do
many.times doHash[h.sort]endend
GC.start
b.report("keys sort")do
many.times do
nh ={}
h.keys.sort.each do|k|
nh[k]= h[k]endendendend
user system total real
hash sort 0.4000000.0000000.400000(0.405588)
keys sort 0.2500000.0100000.260000(0.260303)
Bei großen Hashes wächst der Unterschied auf das 10-fache und mehr
Sie haben sich im OP die beste Antwort gegeben: Hash[h.sort]Wenn Sie sich nach mehr Möglichkeiten sehnen, finden Sie hier eine direkte Änderung des ursprünglichen Hashs, um ihn zu sortieren:
Ich habe den Link so korrigiert, dass er auf Google verweist, falls ein Historiker untersuchen möchte, wie dies in der Vergangenheit hätte geschehen können. Aber jeder, der jetzt darauf kommt, sollte eine neuere Version von Ruby verwenden.
@equipments ist ein Hash, den ich auf meinem Modell aufbaue und auf meinem Controller zurückgebe. Wenn Sie .sort aufrufen, wird der Hash nach seinem Schlüsselwert sortiert.
Mir hat die Lösung im vorherigen Beitrag gefallen.
Ich habe eine Miniklasse gemacht, sie genannt class AlphabeticalHash. Es hat auch eine Methode namens ap, die ein Argument, a Hash, als Eingabe akzeptiert : ap variable. Ähnlich wie pp ( pp variable)
Aber es wird (versuchen und) in alphabetischer Liste (seine Schlüssel) drucken. Keine Ahnung, wenn jemand anderes dies verwenden möchte, ist es als Juwel erhältlich. Sie können es als solches installieren:gem install alphabetical_hash
Für mich ist das einfach genug. Wenn andere mehr Funktionen benötigen, lassen Sie es mich wissen, ich werde es in den Edelstein aufnehmen.
EDIT: Dank geht an Peter , der mir die Idee gegeben hat. :) :)
each
odereach_pair
iterieren darüber. Selbst dann würde ich wahrscheinlich immer noch die Schlüssel greifen, diese sortieren und dann darüber iterieren und die Werte nach Bedarf abrufen. Dadurch wird sichergestellt, dass sich der Code auf älteren Rubinen korrekt verhält.Antworten:
In Ruby 2.1 ist es einfach:
quelle
h.sort{|a,z|a<=>z}.to_h
(getestet 2.1.10, 2.3.3)a
ist ein Array, nicht nur der Schlüssel). Ich habe meinen Kommentar gelöscht.h.map(&:sort).map(&:to_h)
.Hinweis: Ruby> = 1.9.2 hat einen auftragserhaltenden Hash: Die eingefügten Auftragsschlüssel entsprechen der Reihenfolge, in der sie aufgelistet sind. Das Folgende gilt für ältere Versionen oder für abwärtskompatiblen Code.
Es gibt kein Konzept für einen sortierten Hash. Also nein, was du tust, ist nicht richtig.
Wenn Sie möchten, dass es zur Anzeige sortiert wird, geben Sie eine Zeichenfolge zurück:
oder, wenn Sie die Schlüssel in der richtigen Reihenfolge haben möchten:
oder, wenn Sie der Reihe nach auf die Elemente zugreifen möchten:
Zusammenfassend macht es jedoch keinen Sinn, über einen sortierten Hash zu sprechen. In den Dokumenten heißt es: "Die Reihenfolge, in der Sie einen Hash nach Schlüssel oder Wert durchlaufen, scheint willkürlich zu sein und liegt im Allgemeinen nicht in der Einfügereihenfolge." Das Einfügen von Schlüsseln in einer bestimmten Reihenfolge in den Hash hilft also nicht.
quelle
Ich habe immer benutzt
sort_by
. Sie müssen die#sort_by
Ausgabe umschließenHash[]
, damit sie einen Hash ausgibt, andernfalls wird ein Array von Arrays ausgegeben. Um dies zu erreichen, können Sie alternativ die#to_h
Methode für das Array von Tupeln ausführen , um sie in einek=>v
Struktur (Hash) zu konvertieren .Es gibt eine ähnliche Frage in " Wie sortiere ich einen Ruby Hash nach Zahlenwert? ".
quelle
sort_by
einen Hash verwenden, wird ein Array zurückgegeben. Sie müssten es erneut als Hash zuordnen.Hash[hsh.sort_by{|k,v| v}]
hsh.sort_by(&:last).to_h => {"b"=>10, "a"=>1000, "c"=>200000}
.to_h
nur in Ruby 2.1.0+sort_by{|k,v| v}.to_h)
Nein, ist es nicht (Ruby 1.9.x)
Bei großen Hashes wächst der Unterschied auf das 10-fache und mehr
quelle
Sie haben sich im OP die beste Antwort gegeben:
Hash[h.sort]
Wenn Sie sich nach mehr Möglichkeiten sehnen, finden Sie hier eine direkte Änderung des ursprünglichen Hashs, um ihn zu sortieren:quelle
Mit Destrukturierung und Hash # Sortierung
Enumerable # sort_by
Hash # sort mit Standardverhalten
Hinweis: <Ruby 2.1
Hinweis:> Ruby 2.1
quelle
v
, sollten Sie einen Unterstrichhash.sort_by { |k, _v| k }.to_h
ActiveSupport :: OrderedHash ist eine weitere Option, wenn Sie Ruby 1.9.2 nicht verwenden oder eigene Problemumgehungen durchführen möchten.
quelle
quelle
Ich hatte das gleiche Problem (ich musste meine Geräte nach ihrem Namen sortieren) und löste es folgendermaßen:
@equipments ist ein Hash, den ich auf meinem Modell aufbaue und auf meinem Controller zurückgebe. Wenn Sie .sort aufrufen, wird der Hash nach seinem Schlüsselwert sortiert.
quelle
Mir hat die Lösung im vorherigen Beitrag gefallen.
Ich habe eine Miniklasse gemacht, sie genannt
class AlphabeticalHash
. Es hat auch eine Methode namensap
, die ein Argument, aHash
, als Eingabe akzeptiert :ap variable
. Ähnlich wie pp (pp variable
)Aber es wird (versuchen und) in alphabetischer Liste (seine Schlüssel) drucken. Keine Ahnung, wenn jemand anderes dies verwenden möchte, ist es als Juwel erhältlich. Sie können es als solches installieren:
gem install alphabetical_hash
Für mich ist das einfach genug. Wenn andere mehr Funktionen benötigen, lassen Sie es mich wissen, ich werde es in den Edelstein aufnehmen.
EDIT: Dank geht an Peter , der mir die Idee gegeben hat. :) :)
quelle