Absteigende Sortierung nach Wert eines Hash in Ruby

75

Mein Eingabe-Hash: h = { "a" => 20, "b" => 30, "c" => 10 }

Aufsteigende Sorte: h.sort {|a,b| a[1]<=>b[1]} #=> [["c", 10], ["a", 20], ["b", 30]]

Aber ich brauche [["b", 30], ["a", 20], ["c", 10]]

Wie können wir dafür sorgen, dass es umgekehrt funktioniert <=>? Was bedeutet das?

zengr
quelle

Antworten:

186

Sie können es sauberer, klarer und schneller auf einmal haben! So was:

h.sort_by {|k,v| v}.reverse

Ich habe Timings mit 3000 Iterationen zum Sortieren eines 1000-Elemente-Hashs mit zufälligen Werten verglichen und diese Zeiten erhalten:

h.sort {|x,y| -(x[1]<=>y[1])} -- 16.7s
h.sort {|x,y| y[1] <=> x[1]} -- 12.3s
h.sort_by {|k,v| -v} -- 5.9s
h.sort_by {|k,v| v}.reverse -- 3.7
Glenn McDonald
quelle
2
Optisch ist dies sauberer, aber es führt zu einer zusätzlichen Durchquerung der Sammlung, um sie umzukehren.
Der Blechmann
@glennmcdonald Kannst du mir bitte sagen, wie man die Zeiten für jeden Anruf in Ruby berechnen kann?
Boddhisattva
1
Ich fand heraus, wie man die Zeit für jeden Anruf berechnet. Hier ist ein Beispiel-Link: - ruby-doc.org/core-1.9.3/Enumerable.html#method-i-sort
boddhisattva
Was ist mit h.sort_by(&:last).reverse? Irgendwelche Zeiten dazu?
Cruz Nunez
Welche Ruby-Version?
Danielricecodes
12
h.sort {|a,b| b[1]<=>a[1]}
Demas
quelle
7
Ich habe diesen Kommentar abgelehnt, nicht weil die Antwort falsch ist, sondern weil Sie nicht erklären, warum dies die richtige Antwort ist. Der Fragesteller fragte sogar speziell, was "<=>" bedeutet - also ist er klar nach einer Erklärung, wie das alles funktioniert. Es ist eine gute Idee, auf diese Weise zu helfen :)
Taryn East
PS: Weitere Informationen finden Sie in der
Taryn East
9

<=>vergleicht die beiden Operanden und gibt -1 zurück, wenn der erste niedriger ist, 0, wenn sie gleich sind, und 1, wenn der erste höher ist. Dies bedeutet, dass Sie einfach -(a[1]<=>b[1])die Reihenfolge umkehren können.

Futter
quelle
1
Ich sehe es immer lieber, wenn die Elemente "a" und "b" vertauscht sind, als das Ergebnis zu negieren. Wenn sie getauscht sind, muss ich nur ihre Reihenfolge überprüfen, um zu sehen, dass sie rückwärts sind, um zu wissen, dass sie umgekehrt ist. Wenn der Wert von <=>negiert ist, muss ich mir noch den tatsächlichen Vergleich ansehen, um zu wissen, was los ist. Es ist ein kleiner Punkt, aber etwas, das mir bewusst ist, weil ich spüre, dass mein Gehirn die zweite Überprüfung durchführen muss, nachdem ich ein "Was!?"
Der Blechmann
1
@ Greg: Ich verstehe definitiv, warum du es anders bevorzugen würdest. Ich bin das Gegenteil: Für meine Scan-Augen b[1]<=>a[1]sieht es hella aus a[1]<=>b[1]und ich habe das Bedürfnis anzuhalten und zu überprüfen, während die Negation sofort deutlich macht, dass wir eine umgekehrte Sortierung durchführen.
Chuck
Ich verstehe auch Ihren Standpunkt. In beiden Fällen müssen die verglichenen Werte noch sorgfältig geprüft werden. Vielleicht brauchen wir einen anderen Operator - >=<für die umgekehrte Reihenfolge? Nein, das wäre genauso schlimm. Es ist das gesamte Konstrukt, aber ich bevorzuge <=>einen ausführlicheren Ansatz, bei dem wir einige Methodennamen aufrufen müssten.
Der Blechmann
7

Super einfach: h.sort_by { |k, v| -v }

Paul Odeon
quelle