У меня есть массив хэшей:
[
{ :foo => 'foo', :bar => 2 },
{ :foo => 'foo', :bar => 3 },
{ :foo => 'foo', :bar => 5 },
]
Я пытаюсь отсортировать этот массив в порядке убывания в соответствии со значением :bar
в каждом хеше.
Я использую sort_by
для сортировки выше массив:
a.sort_by { |h| h[:bar] }
Однако это сортирует массив в порядке возрастания. Как мне сделать сортировку в порядке убывания?
Одним из решений было сделать следующее:
a.sort_by { |h| -h[:bar] }
Но этот отрицательный знак не кажется уместным.
sort_by.reverse
он значительно более эффективен, чем принятый в настоящее время ответ. Я полагаю, что это также лучше решает проблему, о которой вы упоминали выше, «передавая намерение кода». Кроме того, Железный Человек обновил свой ответ для текущей версии ruby. Этот вопрос был просмотрен более 15 раз. Если вы можете сэкономить хотя бы 1 секунду времени каждого зрителя, я думаю, это того стоит.Ответы:
Всегда полезно сделать оценку различных предложенных ответов. Вот что я узнал:
Я думаю, интересно, что @ Pablo's
sort_by{...}.reverse!
самый быстрый. Перед запуском теста я подумал, что это будет медленнее, чем "-a[:bar]
", но отрицание значения оказывается дольше, чем обратное преобразование всего массива за один проход. Это не большая разница, но каждое небольшое ускорение помогает.Вот результаты для Ruby 1.9.3p194 (2012-04-20 ревизия 35410) [x86_64-darwin10.8.0]:
Это на старом MacBook Pro. Более новые или более быстрые машины будут иметь более низкие значения, но относительные различия останутся.
Вот немного обновленная версия на более новом оборудовании и версии Ruby 2.1.1:
Новые результаты запуска вышеуказанного кода с использованием Ruby 2.2.1 на более позднем Macbook Pro. Опять же, точные цифры не важны, это их отношения:
Обновлен для Ruby 2.7.1 на MacBook Pro середины 2015 года:
Источник для
Array#reverse
:do *p2-- = *p1++; while (--len > 0);
копирует указатели на элементы в обратном порядке, если я правильно помню свой C, поэтому массив перевернут.источник
Просто быстрая вещь, которая обозначает намерение по убыванию.
(Пока подумаем о лучшем способе);)
источник
Вы могли бы сделать:
источник
sort_by
был в том, что он избегал многократного запуска функции сравненияsort_by
гораздо эффективнее и читабельнее. Отрицание значения или обратное в конце будет быстрее и более читабельным.* -1
он не работает со всеми значениями (например, временем) иreverse
будет переупорядочивать значения, отсортированные как равныеЯ вижу, что у нас (помимо других) в основном два варианта:
и
Хотя оба способа дают один и тот же результат, когда ваш ключ сортировки уникален, имейте в виду, что этот
reverse
способ обратит порядок ключей, которые равны .Пример:
Хотя вам часто не нужно заботиться об этом, иногда вам это нужно. Чтобы избежать такого поведения, вы можете ввести второй ключ сортировки (который наверняка должен быть уникальным по крайней мере для всех элементов, имеющих одинаковый ключ сортировки):
источник
reverse
отличается. Я полагаю, что это также испортит предыдущий вид, в случае, когда кто-то пытается применить несколько видов в некотором порядке.Что о:
Оно работает!!
источник
sort
будет работать, это только быстрее при сортировке непосредственных значений. Если вам нужно копать ихsort_by
быстрее. Смотрите тест.Что касается упомянутого набора тестов, эти результаты также применимы для отсортированных массивов.
sort_by
/reverse
это:И результаты:
источник
Простое решение от восходящего до нисходящего и наоборот:
НИТИ
ЦИФРЫ
источник
Для тех, кто любит измерять скорость в IPS;)
И результаты:
источник