Как отсортировать 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)

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 }

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


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 «нетипизированным». О нет, это определенно напечатано. Это просто не типизировано. :)
Джейкоб Мэттисон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.