5 Stimmen

Sortieren einer Liste von Objekten anhand ihrer Attribute in Ruby

Ich habe eine Liste von Fruit Strukturen namens basket . Jede Fruit Struktur hat eine name (eine Zeichenkette) und eine calories (eine ganze Zahl). Ich würde gerne sortieren basket damit:

  1. Le site Fruit s mit den höchsten calories erscheinen zuerst. Zum Beispiel erscheint eine Frucht mit 500 Kalorien vor einer Frucht mit 400 Kalorien.

  2. Wenn zwei Fruit s haben die gleiche calories die Fruit deren name zuerst kommt alphabetisch zuerst, Groß- und Kleinschreibung wird nicht berücksichtigt. Bei zwei Früchten mit gleichem Kaloriengehalt kommt zum Beispiel die Frucht mit dem Namen "Banane" vor der Frucht mit dem Namen "Zitrus".

Die Definition von Fruit ist etwas, das ich nicht kontrollieren kann, daher würde ich eine Lösung bevorzugen, bei der ich nichts in das Wasser mischen muss. Fruit oder sie zu ändern. Ist dies möglich?

12voto

Gareth Punkte 123487

Die einfache Lösung ist

basket.sort_by { |f| [-f.calories, f.name] }

Natürlich, wenn es sich um die kanonische Sortierung für Obst, dann ist es sollte definiert werden, indem die <=> Methode und mit der Comparable Modul gemischt mit Fruit

2voto

Adrian Dunston Punkte 2932

Gehen wir davon aus, dass Ihr Korb ein Array oder eine Unterklasse davon ist.

Der schnelle Weg

Aufzählbar.sort_by

Als Gareth darauf hingewiesen, hat Enumerable (enthalten in Array) eine sort_by-Methode, die jedes Listenelement einmal durchläuft. Dies ist schneller auszuführen und schneller zu schreiben, sobald man den Dreh raus hat.

# -f.calories to sort descending
# name.downcase to do a case-insensitive sort
basket = basket.sort_by { |f| [-f.calories, f.name.downcase] }

Der Perl-Weg

Array.sort

Da ich aus dem Perl-Umfeld komme, ist mein erster Impuls, den Raumschiff-Operator <=> zu benutzen. Ein frecher kleiner Teufel. Array hat die Methoden sort und sort!, die es sehr nützlich machen. Diese Lösung ist langsamer, und da sie länger ist, führt sie eher zu Fehlern. Der einzige Grund, sie zu verwenden, ist, wenn Sie es mit Leuten zu tun haben, die mit Ruby nicht vertraut sind und nicht bereit sind, die rechts Weg auf StackOverflow.

baseket.sort! { |a,b|
  if a.calories == b.calories
    a.name.downcase <=> b.name.downcase
  else
    # Reverse the result to sort highest first.
    -(a.calories <=> b.calories)
  end
}

1voto

Marc W Punkte 18889

Siehe Array#sort ( API-Dokument ). Sie können einen Block übergeben, der -1, 0 oder 1 zurückgibt, wenn zwei Fruit Objekte, und Ihr Block kann diese Werte anhand beliebiger Attribute bestimmen.

1voto

levinalex Punkte 5671

Wenn Sie häufig Früchte sortieren müssen, sollten Sie sich im Vorfeld etwas mehr Mühe geben und Ihre Objekte vergleichbar machen.

Dazu müssen Sie den Spaceship-Operator implementieren ( <=> ) und schließen Comparable ein.

class Fruit
  attr_accessor :name, :color

  def <=>(other)
    # use Array#<=> to compare the attributes
    [self.name.downcase, self.color] <=> [other.name.downcase, other.color]
  end

  include Comparable
end

dann können Sie einfach tun:

list_of_fruits.sort

Comparable gibt Ihnen auch viele andere Methoden ( == , < , > ) kostenlos, so dass Sie Dinge tun können wie if (apple < banana) (siehe die Dokumentation für das Modul Comparable für weitere Informationen)

<=>, wird angegeben, um Folgendes zurückzugeben -1 wenn self kleiner ist als other , +1 wenn other kleiner ist und 0 wenn beide Objekte gleich sind.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X