Trier un tableau d'objets dans Ruby par attribut d'objet?


129

J'ai un tableau d'objets dans Ruby on Rails. Je veux trier le tableau par un attribut de l'objet. C'est possible?

Réponses:


223

Je recommande d'utiliser sort_by à la place:

objects.sort_by {|obj| obj.attribute}

Surtout si l'attribut peut être calculé.

Ou une approche plus concise:

objects.sort_by(&:attribute)

81
Ou la version abrégée:objects.sort_by(&:attribute)
Nikola

3
objets encore plus courts.sort_by &: attribut
jasin_89

1
Si vous rencontrez des problèmes avec les lettres majuscules et minuscules triées séparément, vous pouvez utiliserobjects.sort_by { |obj| obj.attribute.downcase }
campeterson

1
Avez-vous une idée de la comparaison avec sort!(par exemple, la vitesse, etc.)?
Joshua Pinter du


35

Oui, Array#sort!il est facile de l'utiliser.

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

Thnx buddy mais cela n'a pas fonctionné pour moi, j'ai un éventail d'objets. Dans lequel l'un des attributs de l'objet est créé_at. Je veux le trier avec ce champ. alors j'ai fait @ comm_bytes.sort! {| a, b | a.created_at <=> b.created_at} mais pas de chance pour moi, pouvez-vous m'aider .... ??

4
Existe-t-il une méthode created_at pour accéder à l'attribut @created_at? Quel genre d'objet est @created_at? Définit-il <=>? Quel genre d'erreurs obtenez-vous? etc, etc, ad nauseum. En d'autres termes, nous avons besoin de plus de détails que "mais pas de chance pour moi".
rampion

cela fonctionne si vous faites myarray = myarray.sort {...} sans "!"
DoruChidean

@Doru Oui, cela fonctionne aussi, mais pourquoi feriez-vous cela? C'est moins direct et moins efficace. À utiliser sortsi vous souhaitez conserver l'original et affecter le résultat à un objet différent; sinon, utilisez la variante en place, sort!. En fait, sortappelle en sort!interne, après avoir copié l'objet d'origine.
Konrad Rudolph

1
@Doru Il doit y avoir une erreur ailleurs dans le code, je peux vous garantir à 100% que sort!cela fonctionnera très bien, et toujours (!) Faire la même chose que ce que vous avez écrit.
Konrad Rudolph

27

Ordre croissant :

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

ou

objects_array.sort_by{ |obj| obj.attribute }

Ordre décroissant :

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

ou

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

20

au cas où vous auriez besoin de trier par deux attributs, où le premier est plus important que le second (signifie ne prendre en compte les seconds arguments que si les premiers arguments sont égaux), alors vous pouvez faire comme ceci

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

ou en cas de tableau de tableaux

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

14

Vous pouvez rendre n'importe quelle classe triable en remplaçant la méthode <=>:

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

Désormais, un tableau d'objets Person pourra être trié sur 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

Le tri de tableau fonctionne bien, comme indiqué ci-dessus:

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

MAIS, vous devez vous assurer que l' <=>opérateur est implémenté pour cet attribut. S'il s'agit d'un type de données natif Ruby, ce n'est pas un problème. Sinon, écrivez votre propre implémentation qui renvoie -1 si a <b, 0 si elles sont égales et 1 si a> b.


10

Plus élégant objects.sort_by(&:attribute), vous pouvez en ajouter un .reversesi vous avez besoin de changer de commande.



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

2
Il y a beaucoup de réponses identiques publiées en 2009. Inutile d'en ajouter une autre.
entre

2
Ne pas utiliser sortlorsque vous triez des objets qui ne peuvent pas être directement comparés. Si vous devez accéder à des attributs ou faire un calcul pour obtenir la valeur à comparer, utilisez sort_by. Ce sera beaucoup plus rapide.
The Tin Man
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.