Mam listę prostych instancji klas przypadków scala i chcę je wydrukować w przewidywalnej, leksykograficznej kolejności przy użyciu list.sorted
, ale otrzymuję „Brak domyślnego porządku zdefiniowanego dla ...”.
Czy istnieje niejawne, które zapewnia porządkowanie leksykograficzne dla klas przypadków?
Czy istnieje prosty idiomatyczny sposób na dodanie porządku leksykograficznego do klasy przypadków?
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)
^
Nie podoba mi się „hack”:
scala> l.map(_.toString).sorted.foreach(println)
A(article,2)
A(lines,7)
A(words,50)
scala
sorting
case-class
ya_pulser
źródło
źródło
Odpowiedzi:
Moją ulubioną metodą jest skorzystanie z dostarczonej niejawnej kolejności dla krotek, ponieważ jest ona jasna, zwięzła i poprawna:
To działa, ponieważ towarzysz
Ordered
definiuje niejawna konwersja zOrdering[T]
celuOrdered[T]
, który jest w zakresie do dowolnej klasy wykonawczegoOrdered
. Istnienie niejawnegoOrdering
s dlaTuple
s umożliwia konwersję zTupleN[...]
doOrdered[TupleN[...]]
pod warunkiem, że niejawneOrdering[TN]
istnieje dla wszystkich elementówT1, ..., TN
krotki, co zawsze powinno mieć miejsce, ponieważ nie ma sensu sortować według typu danych bezOrdering
.Niejawne porządkowanie dla krotek jest Twoim celem dla każdego scenariusza sortowania obejmującego złożony klucz sortowania:
Ponieważ ta odpowiedź stała się popularna, chciałbym ją rozwinąć, zauważając, że rozwiązanie podobne do poniższego może w pewnych okolicznościach zostać uznane za klasy korporacyjnej ™:
Podane
es: SeqLike[Employee]
,es.sorted()
posortuje według nazwy ies.sorted(Employee.orderingById)
posortuje według identyfikatora. Ma to kilka zalet:Ordering
, więc podanie kolejności bezpośrednio eliminuje niejawną konwersję w większości przypadków.źródło
value compare is not a member of (String, Int)
.Ma to tę zaletę, że jest aktualizowane automatycznie po każdej zmianie A. Ale pola A muszą być ułożone w kolejności, w jakiej zamawiający je wykorzysta.
źródło
<console>:12: error: not found: value unapply
Podsumowując, można to zrobić na trzy sposoby:
Zdefiniuj zamówienie niestandardowe. Zaletą tego rozwiązania jest to, że możesz ponownie używać kolejności i mieć wiele sposobów sortowania wystąpień tej samej klasy:
Odpowiadając na twoje pytanie Czy jest jakaś standardowa funkcja zawarta w Scali, która potrafi magicznie, jak List ((2,1), (1,2)). Sortowane
Istnieje zestaw predefiniowanych kolejności , np. Dla String, krotek do 9 ar, i tak dalej.
Nie ma czegoś takiego dla klas przypadków, ponieważ nie jest łatwo wycofać się, biorąc pod uwagę, że nazwy pól nie są znane a-priori (przynajmniej bez magii makr) i nie można uzyskać dostępu do pól klas przypadków w inny sposób niż przez nazwa / używanie iteratora produktu.
źródło
unapply
Metoda obiektu towarzyszącego zapewnia konwersję z klasy sprawę doOption[Tuple]
, gdzieTuple
jest krotka odpowiadający pierwszej listy argumentów klasy sprawy. Innymi słowy:źródło
Metoda sortBy byłaby typowym sposobem wykonania tego, np. (Sortowanie według
tag
pola):źródło
l.sortBy( e => e._tag + " " + e._load + " " + ... )
?sortBy
, to tak, albo to, albo dodaj / użyj odpowiedniej funkcji do / na klasie (np._.toString
Lub własnej niestandardowej metody lub funkcji zewnętrznej o znaczeniu leksograficznym).List((2,1),(1,2)).sorted
obiekty klasy przypadku? Nie widzę dużej różnicy między nazwanymi krotkami (klasa przypadku == nazwana krotka) a prostymi krotkami.Option[TupleN]
znak, a następnie wywołanieget
tego:l.sortBy(A.unapply(_).get)foreach(println)
które używa podanej kolejności w odpowiedniej krotce, ale jest to po prostu wyraźny przykład ogólnej idei, którą podałem powyżej .Ponieważ użyłeś klasy case, którą możesz rozszerzyć za pomocą Ordered w następujący sposób :
źródło