Jak posortować Ruby Hash według wartości liczbowej?

154

Mam licznik hash, który próbuję posortować według liczby. Problem, z którym się spotykam, polega na tym, że domyślna funkcja Hash.sort sortuje liczby jako ciągi znaków, a nie według rozmiaru liczb.

tj. Given Hash:

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

Uruchamianie tego kodu:

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

zwróci posortowaną tablicę:

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

Mimo że 745 to liczba większa niż 9, 9 pojawi się jako pierwsze na liście. Kiedy próbuję pokazać, kto jest najważniejszy, utrudnia mi to życie. :)

Jakieś pomysły na sortowanie skrótu (lub nawet tablicy) według rozmiaru wartości liczbowej?

Doceniam każdą pomoc.

Dustin M.
źródło
jakiej wersji ruby ​​używasz? Twój wynik sortowania jest bardzo dziwny
fl00r

Odpowiedzi:

268

Nie mam pojęcia, jak otrzymałeś wyniki, ponieważ nie posortowałoby to według wartości ciągu ... Powinieneś odwrócić a1i a2w swoim przykładzie

W każdym przypadku najlepszym sposobem (według Mladena) jest:

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]]

Jeśli w rezultacie potrzebujesz skrótu, możesz użyć to_h(w Ruby 2.0+)

metrics.sort_by {|_key, value| value}.to_h
  # ==> {"siteb.com" => 9, "sitec.com" => 10, "sitea.com", 745}
Marc-André Lafortune
źródło
84
lub po prostusort_by{|k,v| v}
Mladen Jablanović
Moja liczba zwracała się jako ciąg znaków, który to naprawił. Miałem a2 i a1 w tej kolejności, ponieważ chciałem, aby wyniki były sortowane w porządku malejącym ... dzięki za Twoją opinię.
Dustin M.
dlatego kocham Ruby ... taki problem to ból głowy w innych językach. so simple
Hady Elsahar
18
@Elchin: możesz użyćmetrics.sort_by{ |k, v| v }.reverse.to_h
Marc-André Lafortune
4
Właściwie nawet prostsze, jak: hash.sort_by (&: last) z tym samym zastrzeżeniem dotyczącym uzyskiwania tablicy par kontra Hash.
Gerry Gleason
84

Ponieważ wartość jest ostatnim wpisem, możesz:

metrics.sort_by(&:last)
shock_one
źródło
4
To jest niesamowite! jakieś odniesienie do wstępnej definicji &:last?
Tamer Shlash,
sort_by(&:last)jest efektywnym skrótem dla sort_by {|x| x.last} stackoverflow.com/questions/1217088/…
Beni Cherniavsky-Paskin
14

Już odpowiedziałem, ale nadal. Zmień kod na:

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

Konwertowane na ciągi po drodze lub nie, to wykona zadanie.

dimitarvp
źródło
9

To nie jest zachowanie, które widzę:

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]]

Czy to możliwe, że gdzieś wzdłuż linii twoje liczby są konwertowane na łańcuchy? Czy jest więcej kodu, którego nie publikujesz?

Jacob Mattison
źródło
Ach, masz rację, wygląda na to, że wynik w moim kodzie zwracał go jako ciąg. Brzydkie typy danych. :) Czasami jestem po prostu zbyt blisko problemu. Dzięki.
Dustin M.
1
Tak. Czasami słyszę, że ktoś odnosi się do Rubiego jako „bez typu”. O nie, to zdecydowanie wpisane. Po prostu nie jest wpisany statycznie. :)
Jacob Mattison,