Как отсортировать Ruby Hash по числовому значению?

154

У меня есть встречный хеш, который я пытаюсь отсортировать по количеству. Проблема, с которой я сталкиваюсь, заключается в том, что функция Hash.sort по умолчанию сортирует числа как строки, а не по размеру.

т.е. учитывая хэш:

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

Запуск этого кода:

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

вернет отсортированный массив:

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

Даже если число 745 больше, чем 9, 9 появится первым в списке. Когда я пытаюсь показать, кто имеет наибольшее количество очков, это усложняет мою жизнь. :)

Любые идеи о том, как отсортировать хэш (или даже массив) по размеру числового значения?

Я ценю любую помощь.

Дастин М.
источник
какую версию ruby ​​вы используете? Ваш результат очень странный
fl00r

Ответы:

268

Не знаю, как вы получили свои результаты, так как он не будет сортировать по строковому значению ... Вы должны обратить вспять a1и a2в вашем примере

Лучший способ в любом случае (согласно Младену):

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

Если вам нужен хеш в результате, вы можете использовать to_h(в Ruby 2.0+)

metrics.sort_by {|_key, value| value}.to_h
  # ==> {"siteb.com" => 9, "sitec.com" => 10, "sitea.com", 745}
Марк-Андре Лафортун
источник
84
или простоsort_by{|k,v| v}
Младен Ябланович
Мой номер возвращался в виде строки, которая исправила его ... У меня были a2 и a1 в этом порядке, потому что я хотел, чтобы результаты сортировались по убыванию ... хотя спасибо за ваш отзыв.
Дастин М.
Вот почему я люблю Руби ... такая проблема - боль в голове на других языках. так просто
Хади Эльсахар
18
@Elchin: вы можете использоватьmetrics.sort_by{ |k, v| v }.reverse.to_h
Марк-Андре Lafortune
4
На самом деле даже проще, чем: hash.sort_by (&: last) с тем же предупреждением о получении массива пар против Hash.
Джерри Глисон
84

Поскольку значение является последней записью, вы можете сделать:

metrics.sort_by(&:last)
shock_one
источник
4
Это круто! любой референц для предварительного определения &:last?
Укротитель Шлэш
sort_by(&:last)фактически является сокращением для sort_by {|x| x.last} stackoverflow.com/questions/1217088/…
Бени Чернявский-Паскин
14

Уже ответил, но все же. Измените свой код на:

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

Преобразованные в строки по пути или нет, это сделает работу.

dimitarvp
источник
9

Это не то поведение, которое я вижу:

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

Возможно ли, что где-то вдоль линии ваши числа будут преобразованы в строки? Есть ли еще код, который вы не публикуете?

Джейкоб Маттисон
источник
Ах, вы правы, похоже, что результат в моем коде возвращал его в виде строки. Пеские типы данных. :) Иногда я просто слишком близко к проблеме. Спасибо.
Дастин М.
1
Ага. Иногда я слышу, как кто-то называет Ruby «нетипизированным». О нет, это определенно напечатано. Это просто не типизировано. :)
Джейкоб Мэттисон