Сортировка массива объектов в Ruby по атрибуту объекта?


129

У меня есть массив объектов в Ruby on Rails. Я хочу отсортировать массив по атрибуту объекта. Является ли это возможным?

Ответы:


223

Вместо этого я рекомендую использовать sort_by:

objects.sort_by {|obj| obj.attribute}

Особенно, если атрибут можно вычислить.

Или более лаконичный подход:

objects.sort_by(&:attribute)

81
Или сокращенная версия:objects.sort_by(&:attribute)
Nikola

3
еще более короткие объекты.
sort_by

1
Если у вас есть проблемы с раздельной сортировкой прописных и строчных букв, вы можете использоватьobjects.sort_by { |obj| obj.attribute.downcase }
campeterson

1
Есть идеи, как это сравнивать sort!(например, скорость и т. Д.)?
Джошуа Пинтер


35

Да, использовать Array#sort!это просто.

myarray.sort! { |a, b|  a.attribute <=> b.attribute }

Спасибо, приятель, но у меня не получилось, у меня есть массив объектов. В котором создан один из атрибутов объекта_at. Я хочу отсортировать его по этому полю. так что я сделал @ comm_bytes.sort! {| a, b | a.created_at <=> b.created_at} но мне не повезло, вы можете помочь .... ??

4
Есть ли метод created_at для доступа к атрибуту @created_at? Что за объект @created_at? Это определяет <=>? Какие ошибки вы получаете? и т. д. и т. д. до тошноты. Другими словами, нам нужно больше деталей, чем «но мне не повезло».
rampion

он работает, если вы выполните myarray = myarray.sort {...} без "!"
DoruChidean

@Doru Да, это тоже работает, но зачем тебе это делать? Это менее прямолинейно и менее эффективно. Используйте, sortесли хотите сохранить оригинал и присвоить результат другому объекту; в противном случае используйте вариант в месте, sort!. Фактически, sortвызывает sort!внутренний вызов после копирования исходного объекта.
Конрад Рудольф

1
@Doru Где-то еще в коде должна быть ошибка, я могу на 100% гарантировать вам, что она sort!будет работать нормально и всегда (!) Делать то же самое, что вы написали.
Конрад Рудольф

27

По возрастанию:

objects_array.sort! { |a, b|  a.attribute <=> b.attribute }

или

objects_array.sort_by{ |obj| obj.attribute }

В порядке убывания :

objects_array.sort! { |a, b|  b.attribute <=> a.attribute }

или

objects_array.sort_by{ |obj| obj.attribute }.reverse

20

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

myarray.sort{ |a,b| (a.attr1 == b.attr1) ? a.attr2 <=> b.attr2 : a.attr1 <=> b.attr1 }

или в случае массива массивов

myarray.sort{ |a,b| (a[0] == b[0]) ? a[1] <=> b[1] : a[0] <=> b[0] }

14

Вы можете сделать любой класс сортируемым, переопределив метод <=>:

class Person

  attr_accessor :first_name, :last_name

  def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
  end

  def <=>(other)
    @last_name + @first_name <=> other.last_name + other.first_name
  end

end

Теперь массив объектов Person можно будет отсортировать по last_name.

ar = [Person.new("Eric", "Cunningham"), Person.new("Homer", "Allen")]

puts ar  # => [ "Eric Cunningham", "Homer Allen"]  (Person objects!)

ar.sort!

puts ar  # => [ "Homer Allen", "Eric Cunningham" ]

10

Array # sort работает хорошо, как указано выше:

myarray.sort! { |a, b|  a.attribute <=> b.attribute }

НО, вам нужно убедиться, что <=>оператор реализован для этого атрибута. Если это собственный тип данных Ruby, это не проблема. В противном случае напишите собственную реализацию, которая возвращает -1, если a <b, 0, если они равны, и 1, если a> b.


10

Более элегантно objects.sort_by(&:attribute), вы можете добавить, .reverseесли вам нужно изменить порядок.



-2
@model_name.sort! { |a,b| a.attribute <=> b.attribute }

2
В 2009 году опубликовано множество идентичных ответов. Нет необходимости добавлять еще один.
Interjay 06

2
Не используйте sortпри сортировке объектов, которые нельзя сравнивать напрямую. Если вам нужно получить доступ к атрибутам или выполнить вычисление, чтобы получить значение для сравнения, используйте sort_by. Будет намного быстрее.
Железный Человек
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.