web-dev-qa-db-fra.com

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

J'ai un tableau d'objets dans Ruby sur Rails. Je veux trier le tableau en fonction d'un attribut de l'objet. Est-ce possible?

112
Satyam Gautam

Je recommande d'utiliser plutôt sort_by:

objects.sort_by {|obj| obj.attribute}

Surtout si l'attribut peut être calculé.

Ou une approche plus concise:

objects.sort_by(&:attribute)
191
Scott

Oui, en utilisant Array#sort! c'est facile.

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

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
26
shiva kumar

au cas où vous auriez besoin de trier par deux attributs, où le premier est plus important que le second (signifie que le second argument est pris en compte uniquement si les premiers arguments sont égaux), vous pouvez procéder comme suit

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] }
18
bumbu

Vous pouvez rendre n'importe quelle classe triable en redéfinissant 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

Maintenant, un tableau d'objets Person sera triable 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" ]
13
user1182000

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

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

MAIS, vous devez vous assurer que le <=> 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> b.

9
Curt J. Sampson

Plus élégant objects.sort_by(&:attribute), vous pouvez ajouter un .reverse _ si vous devez modifier l'ordre.

8
Noah Davis