Сортування масиву об’єктів у Ruby за атрибутом об’єкта?


Відповіді:


222

Я рекомендую натомість використовувати sort_by:

objects.sort_by {|obj| obj.attribute}

Особливо, якщо атрибут може бути обчислений.

Або більш стислий підхід:

objects.sort_by(&:attribute)

81
Або скорочена версія:objects.sort_by(&:attribute)
Микола

3
ще коротші об’єкти.sort_by &: attribute
jasin_89

1
Якщо у вас є проблеми з сортуванням великих і малих літер, можна скористатисяobjects.sort_by { |obj| obj.attribute.downcase }
campeterson

1
Будь-яка ідея, як це порівнюється sort!(наприклад, швидкість тощо)?
Джошуа Пінтер


35

Так, використовувати Array#sort!це легко.

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

Thnx приятель, але мені це не вийшло, у мене є масив об'єктів. У якому створено один з атрибутів об’єкта_at. Я хочу сортувати це з цим полем. так що я зробив @ comm_bytes.sort! {| a, b | a.create_at <=> b.create_at}, але мені не вдасться допомогти .... ??

4
Чи існує метод create_at для доступу до атрибута @create_at? Що це за об’єкт @create_at? Чи визначає це <=>? Які помилки ви отримуєте? тощо тощо, ad nauseum. Іншими словами, нам потрібно більше деталей, ніж "але мені не пощастило".
чемпіон

він працює, якщо ви робите 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 буде сортувати за прізвищем.

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

Масив # сортування працює добре, як зазначено вище:

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

2
Не використовуйте, sortколи ви сортуєте об'єкти, які неможливо порівняти безпосередньо. Якщо вам потрібно отримати доступ до атрибутів або зробити обчислення, щоб отримати значення для порівняння використання sort_by. Це буде набагато швидше.
Олов'яний чоловік
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.