Сортировка массива объектов в 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!(например, скорость и т. Д.)?
Джошуа Пинтер
Enumerable # sort_by docs
Мэтт Р. Уилсон
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] }
Bumbu
источник
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" ]
user1182000
источник
10

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

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

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

CJS
источник
10

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

Ной Дэвис
источник
-2
@model_name.sort! { |a,b| a.attribute <=> b.attribute }
Харисанкар PS
источник
2
В 2009 году опубликовано множество идентичных ответов. Нет необходимости добавлять еще один.
Interjay 06
2
Не используйте sortпри сортировке объектов, которые нельзя сравнивать напрямую. Если вам нужно получить доступ к атрибутам или выполнить вычисление, чтобы получить значение для сравнения, используйте sort_by. Будет намного быстрее.
Железный Человек