Bagaimana cara mengurutkan Ruby Hash berdasarkan nilai angka?

154

Saya memiliki hash balasan yang ingin saya urutkan berdasarkan hitungan. Masalah yang saya temui adalah bahwa fungsi Hash.sort default mengurutkan angka seperti string daripada berdasarkan ukuran angka.

yaitu Given Hash:

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

Menjalankan kode ini:

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

akan mengembalikan array yang diurutkan:

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

Meskipun 745 adalah jumlah yang lebih besar dari 9, 9 akan muncul pertama dalam daftar. Ketika mencoba untuk menunjukkan siapa yang memiliki hitungan teratas, ini membuat hidup saya sulit. :)

Ada ide tentang cara mengurutkan hash (atau bahkan array) dengan ukuran nilai angka?

Saya menghargai bantuan apa pun.

Dustin M.
sumber
versi ruby ​​apa yang kamu gunakan? hasil
sortirmu

Jawaban:

268

Tidak tahu bagaimana Anda mendapatkan hasil Anda, karena itu tidak akan mengurutkan berdasarkan nilai string ... Anda harus membalikkan a1dan a2dalam contoh Anda

Cara terbaik dalam hal apa pun (sesuai Mladen) adalah:

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

Jika Anda membutuhkan hash, Anda dapat menggunakan to_h(dalam Ruby 2.0+)

metrics.sort_by {|_key, value| value}.to_h
  # ==> {"siteb.com" => 9, "sitec.com" => 10, "sitea.com", 745}
Marc-André Lafortune
sumber
84
atau hanyasort_by{|k,v| v}
Mladen Jablanović
Nomor saya kembali sebagai string, yang memperbaikinya .. Saya memiliki a2 dan a1 dalam urutan itu karena saya ingin hasilnya mengurutkan decending .. terima kasih atas tanggapan Anda.
Dustin M.
ini sebabnya saya suka Ruby ... masalah seperti itu adalah rasa sakit di kepala dalam bahasa lain. sangat sederhana
Hady Elsahar
18
@Elchin: Anda bisa menggunakanmetrics.sort_by{ |k, v| v }.reverse.to_h
Marc-André Lafortune
4
Sebenarnya lebih sederhana seperti: hash.sort_by (&: last) dengan peringatan yang sama tentang mendapatkan array berpasangan vs. Hash.
Gerry Gleason
84

Karena nilai adalah entri terakhir, Anda dapat melakukan:

metrics.sort_by(&:last)
shock_one
sumber
4
Ini luar biasa! ada referensi untuk pra-definisi &:last?
Tamer Shlash
sort_by(&:last)secara efektif singkatan untuk sort_by {|x| x.last} stackoverflow.com/questions/1217088/...
Beni Cherniavsky-Paskin
14

Sudah dijawab tetapi masih. Ubah kode Anda menjadi:

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

Dikonversi menjadi string di sepanjang jalan atau tidak, ini akan melakukan pekerjaan.

dimitarvp
sumber
9

Itu bukan perilaku yang saya lihat:

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

Apakah mungkin bahwa di suatu tempat di sepanjang garis angka Anda sedang dikonversi ke string? Apakah ada lebih banyak kode yang tidak Anda posting?

Jacob Mattison
sumber
Ahh benar sepertinya hasil kode saya mengembalikannya sebagai string. Jenis data sial. :) Terkadang saya terlalu dekat dengan masalah. Terima kasih.
Dustin M.
1
Ya. Terkadang saya mendengar seseorang menyebut Ruby sebagai "tidak diketik". Oh, tidak, sudah pasti diketik. Hanya saja tidak diketik secara statis. :)
Jacob Mattison