Ich habe eine Liste einfacher Scala-Fallklasseninstanzen und möchte sie in vorhersehbarer, lexikografischer Reihenfolge mit drucken list.sorted
, erhalte jedoch "Keine implizite Reihenfolge definiert für ...".
Gibt es ein Implizit, das eine lexikografische Reihenfolge für Fallklassen vorsieht?
Gibt es eine einfache idiomatische Möglichkeit, die lexikografische Reihenfolge in die Fallklasse einzumischen?
scala> case class A(tag:String, load:Int)
scala> val l = List(A("words",50),A("article",2),A("lines",7))
scala> l.sorted.foreach(println)
<console>:11: error: No implicit Ordering defined for A.
l.sorted.foreach(println)
^
Ich bin nicht glücklich mit einem "Hack":
scala> l.map(_.toString).sorted.foreach(println)
A(article,2)
A(lines,7)
A(words,50)
scala
sorting
case-class
ya_pulser
quelle
quelle
Antworten:
Meine persönliche Lieblingsmethode besteht darin, die bereitgestellte implizite Reihenfolge für Tupel zu verwenden, da diese klar, präzise und korrekt ist:
Das funktioniert , weil der Begleiter
Ordered
definiert eine implizite Konvertierung vonOrdering[T]
zuOrdered[T]
denen in Rahmen für jede Klasse ist die UmsetzungOrdered
. Das Vorhandensein von implizitenOrdering
s fürTuple
s ermöglicht eine Konvertierung vonTupleN[...]
zu,Ordered[TupleN[...]]
sofernOrdering[TN]
für alle ElementeT1, ..., TN
des Tupels ein implizites s vorhanden ist. Dies sollte immer der Fall sein, da es keinen Sinn macht, nach einem Datentyp mit no zu sortierenOrdering
.Die implizite Reihenfolge für Tupel ist Ihre Anlaufstelle für jedes Sortierszenario mit einem zusammengesetzten Sortierschlüssel:
Da sich diese Antwort als beliebt erwiesen hat, möchte ich darauf eingehen und darauf hinweisen, dass eine Lösung, die der folgenden ähnelt, unter bestimmten Umständen als Enterprise-Grade ™ angesehen werden kann:
Gegeben
es: SeqLike[Employee]
,es.sorted()
wird nach Namen undes.sorted(Employee.orderingById)
nach ID sortiert. Dies hat einige Vorteile:Ordering
. Wenn Sie also eine Bestellung direkt bereitstellen, wird in den meisten Fällen eine implizite Konvertierung vermieden.quelle
value compare is not a member of (String, Int)
.Dies hat den Vorteil, dass es automatisch aktualisiert wird, wenn sich A ändert. Die Felder von A müssen jedoch in der Reihenfolge platziert werden, in der die Bestellung sie verwendet.
quelle
<console>:12: error: not found: value unapply
Zusammenfassend gibt es drei Möglichkeiten, dies zu tun:
Definieren Sie eine benutzerdefinierte Bestellung. Der Vorteil dieser Lösung besteht darin, dass Sie Bestellungen wiederverwenden und Instanzen derselben Klasse auf mehrere Arten sortieren können:
Beantwortung Ihrer Frage Gibt es eine Standardfunktion in der Scala, die wie List ((2,1), (1,2)) zaubern kann? Sortiert
Es gibt eine Reihe vordefinierter Ordnungen , z. B. für String, Tupel bis zu 9 Arity und so weiter.
Für Fallklassen gibt es so etwas nicht, da das Abrollen nicht einfach ist, da Feldnamen nicht a priori bekannt sind (zumindest ohne Makromagie) und Sie nicht auf andere Weise als durch auf Fallklassenfelder zugreifen können Name / mit Produktiterator.
quelle
Die
unapply
Methode des Begleitobjekts bietet eine Konvertierung von Ihrer Fallklasse in eineOption[Tuple]
, wobei dasTuple
das Tupel ist, das der ersten Argumentliste der Fallklasse entspricht. Mit anderen Worten:quelle
Die sortBy-Methode wäre eine typische Methode, z. B. (Sortieren nach
tag
Feld):quelle
l.sortBy( e => e._tag + " " + e._load + " " + ... )
?sortBy
, dann ja, entweder das, oder fügen Sie der Klasse eine geeignete Funktion hinzu / verwenden Sie sie (z. B._.toString
Ihre eigene lexografisch signifikante benutzerdefinierte Methode oder externe Funktion).List((2,1),(1,2)).sorted
die Objekte der Fallklasse zaubern kann ? Ich sehe keinen großen Unterschied zwischen benannten Tupeln (case class == named tuple) und einfachen Tupeln.Option[TupleN]
, dann rufen Sieget
auf , dass:l.sortBy(A.unapply(_).get)foreach(println)
, die die vorgesehene Reihenfolge auf dem entsprechende Tupel verwendet, aber dies ist nur ein explizites Beispiel für die allgemeine Idee , die ich oben geben .Da Sie eine Fallklasse verwendet haben, können Sie mit Ordered wie folgt erweitern:
quelle