Ein Array von Objekten in Ruby nach Objektattributen sortieren?

128

Ich habe eine Reihe von Objekten in Ruby on Rails. Ich möchte das Array nach einem Attribut des Objekts sortieren. Ist es möglich?

der Blechmann
quelle

Antworten:

222

Ich empfehle stattdessen sort_by zu verwenden:

objects.sort_by {|obj| obj.attribute}

Besonders wenn Attribut berechnet werden kann.

Oder ein prägnanterer Ansatz:

objects.sort_by(&:attribute)
Scott
quelle
81
Oder die Kurzfassung:objects.sort_by(&:attribute)
Nikola
3
noch kürzere objects.sort_by &: attribute
jasin_89
1
Wenn Sie Probleme mit der getrennten Sortierung von Groß- und Kleinbuchstaben haben, können Sieobjects.sort_by { |obj| obj.attribute.downcase }
campeterson
1
Irgendeine Idee, wie dies im Vergleich zu sort!(z. B. Geschwindigkeit usw.) ist?
Joshua Pinter
Enumerable # sort_by docs
Matt R. Wilson
35

Ja, Array#sort!das ist einfach.

myarray.sort! { |a, b|  a.attribute <=> b.attribute }
Konrad Rudolph
quelle
Danke Kumpel, aber es hat bei mir nicht geklappt. Ich habe eine Reihe von Objekten. In dem eines der Attribute des Objekts erstellt wird_at. Ich möchte es mit diesem Feld sortieren. Also habe ich @ comm_bytes.sort gemacht! {| a, b | a.created_at <=> b.created_at}, aber kein Glück für mich, kannst du helfen .... ??
4
Gibt es eine Methode "created_at" für den Zugriff auf das Attribut "@created_at"? Was für ein Objekt ist @created_at? Definiert es <=>? Welche Art von Fehlern bekommen Sie? etc, etc, ad nauseum. Mit anderen Worten, wir brauchen mehr Details als "aber kein Glück für mich".
Rampion
es funktioniert, wenn Sie myarray = myarray.sort {...} ohne "!"
DoruChidean
@Doru Ja, das funktioniert auch, aber warum würdest du das tun? Es ist weniger direkt und weniger effizient. Verwenden sortSie diese Option, wenn Sie das Original beibehalten und das Ergebnis einem anderen Objekt zuweisen möchten. Andernfalls verwenden Sie die In-Place-Variante sort!. In der Tat, sortruft sort!intern, nachdem das ursprüngliche Objekt zu kopieren.
Konrad Rudolph
1
@Doru Es muss irgendwo anders im Code ein Fehler sein. Ich kann Ihnen zu 100% garantieren, dass er einwandfrei sort!funktioniert und immer (!) Das Gleiche tut, was Sie geschrieben haben.
Konrad Rudolph
27

Aufsteigende Reihenfolge:

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

oder

objects_array.sort_by{ |obj| obj.attribute }

Absteigende Reihenfolge :

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

oder

objects_array.sort_by{ |obj| obj.attribute }.reverse
Shiva Kumar
quelle
20

Wenn Sie nach zwei Attributen sortieren müssen, wobei das erste wichtiger als das zweite ist (dh, zweite Argumente werden nur berücksichtigt, wenn die ersten Argumente gleich sind), können Sie dies tun

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

oder im Falle eines Arrays von Arrays

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

Sie können jede Klasse sortierbar machen, indem Sie die <=> -Methode überschreiben:

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

Jetzt kann ein Array von Personenobjekten nach Nachname sortiert werden.

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
quelle
10

Array # sort funktioniert gut, wie oben angegeben:

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

ABER Sie müssen sicherstellen, dass der <=>Operator für dieses Attribut implementiert ist. Wenn es sich um einen nativen Ruby-Datentyp handelt, ist dies kein Problem. Andernfalls schreiben Sie eine eigene Implementierung, die -1 zurückgibt, wenn a <b, 0, wenn sie gleich sind, und 1, wenn a> b.

cjs
quelle
10

Eleganter objects.sort_by(&:attribute)können Sie eine hinzufügen, .reversewenn Sie die Reihenfolge ändern müssen.

Noah Davis
quelle
-2
@model_name.sort! { |a,b| a.attribute <=> b.attribute }
Harisankar PS
quelle
2
Es gibt viele identische Antworten aus dem Jahr 2009. Es ist nicht erforderlich, eine weitere hinzuzufügen.
Interjay
2
Nicht verwenden, sortwenn Sie Objekte sortieren, die nicht direkt verglichen werden können. Wenn Sie auf Attribute zugreifen oder eine Berechnung durchführen müssen, um den zu vergleichenden Wert zu erhalten sort_by. Es wird viel schneller sein.
der Blechmann