J'ai une liste d'instances de classe de cas scala simples et je veux les imprimer dans un ordre lexicographique prévisible en utilisant list.sorted
, mais je reçois "Aucun ordre implicite défini pour ...".
Existe-t-il un implicite qui fournit un ordre lexicographique pour les classes de cas?
Existe-t-il un moyen idiomatique simple de mélanger l'ordre lexicographique dans la classe de cas?
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)
^
Je ne suis pas content d'un 'hack':
scala> l.map(_.toString).sorted.foreach(println)
A(article,2)
A(lines,7)
A(words,50)
scala
sorting
case-class
ya_pulser
la source
la source
Réponses:
Ma méthode préférée personnelle est d'utiliser la commande implicite fournie pour les tuples, car elle est claire, concise et correcte:
Cela fonctionne car le compagnon de
Ordered
définit une conversion implicite deOrdering[T]
versOrdered[T]
laquelle est dans la portée de toute implémentation de classeOrdered
. L'existence deOrdering
s implicite pourTuple
s permet une conversion de àTupleN[...]
àOrdered[TupleN[...]]
condition qu'un impliciteOrdering[TN]
existe pour tous les élémentsT1, ..., TN
du tuple, ce qui devrait toujours être le cas car il n'a aucun sens de trier sur un type de données sansOrdering
.L'ordre implicite pour les tuples est votre choix pour tout scénario de tri impliquant une clé de tri composite:
Comme cette réponse s'est avérée populaire, j'aimerais m'étendre là-dessus, en notant qu'une solution semblable à la suivante pourrait dans certaines circonstances être considérée comme de qualité entreprise ™:
Étant donné
es: SeqLike[Employee]
,es.sorted()
triera par nom etes.sorted(Employee.orderingById)
triera par identifiant. Cela présente quelques avantages:Ordering
, donc fournir un ordre élimine directement une conversion implicite dans la plupart des cas.la source
value compare is not a member of (String, Int)
.Cela présente l'avantage d'être mis à jour automatiquement chaque fois que A change. Mais les champs de A doivent être placés dans l'ordre dans lequel la commande les utilisera.
la source
<console>:12: error: not found: value unapply
Pour résumer, il existe trois façons de procéder:
Définissez une commande personnalisée. L'avantage de cette solution est que vous pouvez réutiliser les classements et avoir plusieurs façons de trier les instances de la même classe:
Répondre à votre question Y a-t-il une fonction standard incluse dans la Scala qui peut faire de la magie comme List ((2,1), (1,2)). Sorted
Il existe un ensemble de classements prédéfinis , par exemple pour String, des tuples jusqu'à 9 arités et ainsi de suite.
Rien de tel n'existe pour les classes de cas, car ce n'est pas chose facile à faire, étant donné que les noms de champs ne sont pas connus a-priori (au moins sans la magie des macros) et que vous ne pouvez pas accéder aux champs de classe de cas d'une manière autre que par nom / utilisation de l'itérateur de produit.
la source
La
unapply
méthode de l'objet compagnon fournit une conversion de votre classe de cas en anOption[Tuple]
, où leTuple
est le tuple correspondant à la première liste d'arguments de la classe de cas. En d'autres termes:la source
La méthode sortBy serait une façon typique de faire cela, par exemple (trier sur
tag
champ):la source
l.sortBy( e => e._tag + " " + e._load + " " + ... )
?sortBy
, alors oui, soit cela, soit ajoutez / utilisez une fonction appropriée à / sur la classe (par exemple_.toString
, ou votre propre méthode personnalisée ou fonction externe lexographiquement significative).List((2,1),(1,2)).sorted
les objets de la classe case? Je ne vois pas de grande différence entre les tuples nommés (classe de cas == tuple nommé) et les tuples simples.Option[TupleN]
, puis appelez-get
le :,l.sortBy(A.unapply(_).get)foreach(println)
qui utilise l'ordre fourni sur le tuple correspondant, mais il s'agit simplement d'un exemple explicite de l'idée générale que je donne ci-dessus .Puisque vous avez utilisé une classe de cas, vous pouvez l'étendre avec Ordered comme ceci :
la source