Wie sortiere ich einen Ruby Hash nach Zahlenwert?

154

Ich habe einen Zähler-Hash, den ich nach Zählung sortieren möchte. Das Problem, auf das ich stoße, ist, dass die Standardfunktion Hash.sort Zahlen eher nach Zeichenfolgen als nach Zahlengröße sortiert.

dh gegebener Hash:

metrics = {"sitea.com" => 745, "siteb.com" => 9, "sitec.com" => 10 }

Ausführen dieses Codes:

metrics.sort {|a1,a2| a2[1]<=>a1[1]}

gibt ein sortiertes Array zurück:

[ 'siteb.com', 9, 'sitea.com', 745, 'sitec.com', 10]

Obwohl 745 eine größere Zahl als 9 ist, wird 9 zuerst in der Liste angezeigt. Wenn ich versuche zu zeigen, wer die höchste Punktzahl hat, macht mir das das Leben schwer. :) :)

Irgendwelche Ideen, wie man einen Hash (oder sogar ein Array) nach der Größe des Zahlenwerts sortiert?

Ich freue mich über jede Hilfe.

Dustin M.
quelle
Welche Ruby-Version benutzt du? Ihr Sortierergebnis ist sehr seltsam
fl00r

Antworten:

268

Keine Ahnung , wie Sie Ihre Ergebnisse erhalten, da es von String - Wert nicht sortieren würde ... Sie umkehren sollen a1und a2in Ihrem Beispiel

Der beste Weg ist auf jeden Fall (nach Mladen):

metrics = {"sitea.com" => 745, "siteb.com" => 9, "sitec.com" => 10 }
metrics.sort_by {|_key, value| value}
  # ==> [["siteb.com", 9], ["sitec.com", 10], ["sitea.com", 745]]

Wenn Sie als Ergebnis einen Hash benötigen, können Sie ihn verwenden to_h(in Ruby 2.0+).

metrics.sort_by {|_key, value| value}.to_h
  # ==> {"siteb.com" => 9, "sitec.com" => 10, "sitea.com", 745}
Marc-André Lafortune
quelle
84
oder einfachsort_by{|k,v| v}
Mladen Jablanović
Meine Nummer kehrte als Zeichenfolge zurück, die das Problem behoben hat. Ich hatte a2 und a1 in dieser Reihenfolge, weil ich wollte, dass die Ergebnisse absteigend sortiert werden. Vielen Dank für Ihr Feedback.
Dustin M.
Deshalb liebe ich Ruby ... ein solches Problem ist Kopfschmerzen in anderen Sprachen. so einfach
Hady Elsahar
18
@ Elchin: Sie können verwendenmetrics.sort_by{ |k, v| v }.reverse.to_h
Marc-André Lafortune
4
Eigentlich noch einfacher als: hash.sort_by (&: last) mit der gleichen Einschränkung, ein Array von Paaren gegen einen Hash zu erhalten.
Gerry Gleason
84

Da value der letzte Eintrag ist, können Sie Folgendes tun:

metrics.sort_by(&:last)
schock_one
quelle
4
Das ist fantastisch! Gibt es einen Hinweis für die Vordefinition von &:last?
Tamer Shlash
sort_by(&:last)ist effektiv Abkürzung für sort_by {|x| x.last} stackoverflow.com/questions/1217088/…
Beni Cherniavsky-Paskin
14

Bereits beantwortet, aber immer noch. Ändern Sie Ihren Code in:

metrics.sort {|a1,a2| a2[1].to_i <=> a1[1].to_i }

Auf dem Weg in Strings konvertiert oder nicht, wird dies den Job erledigen.

dimitarvp
quelle
9

Das ist nicht das Verhalten, das ich sehe:

irb(main):001:0> metrics = {"sitea.com" => 745, "siteb.com" => 9, "sitec.com" =>
 10 }
=> {"siteb.com"=>9, "sitec.com"=>10, "sitea.com"=>745}
irb(main):002:0> metrics.sort {|a1,a2| a2[1]<=>a1[1]}
=> [["sitea.com", 745], ["sitec.com", 10], ["siteb.com", 9]]

Ist es möglich, dass Ihre Zahlen irgendwo entlang der Linie in Zeichenfolgen umgewandelt werden? Gibt es mehr Code, den Sie nicht veröffentlichen?

Jacob Mattison
quelle
Ahh, du hast Recht, es sieht so aus, als hätte das Ergebnis in meinem Code es als Zeichenfolge zurückgegeben. Lästige Datentypen. :) Manchmal bin ich dem Problem einfach zu nahe. Vielen Dank.
Dustin M.
1
Jep. Gelegentlich höre ich jemanden, der Ruby als "untypisiert" bezeichnet. Oh nein, es ist definitiv getippt. Es ist einfach nicht statisch typisiert. :)
Jacob Mattison