Eu tenho uma lista de instâncias de classe de caso scala simples e quero imprimi-las em ordem lexicográfica previsível usando list.sorted
, mas recebo "Nenhum pedido implícito definido para ...".
Existe um implícito que fornece ordenação lexicográfica para classes de caso?
Existe uma maneira idiomática simples de misturar a ordenação lexicográfica na classe de caso?
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)
^
Não estou feliz com um 'hack':
scala> l.map(_.toString).sorted.foreach(println)
A(article,2)
A(lines,7)
A(words,50)
scala
sorting
case-class
ya_pulser
fonte
fonte
Respostas:
Meu método favorito é fazer uso da ordenação implícita fornecida para tuplas, pois é claro, conciso e correto:
Isso funciona porque o companheiro para
Ordered
define uma conversão implícita deOrdering[T]
paraOrdered[T]
que está no escopo de qualquer implementação de classeOrdered
. A existência deOrdering
s implícitos paraTuple
s permite uma conversão deTupleN[...]
em,Ordered[TupleN[...]]
desde queOrdering[TN]
exista um implícito para todos os elementosT1, ..., TN
da tupla, o que sempre deve ser o caso, pois não faz sentido classificar por um tipo de dados com noOrdering
.A ordenação implícita para Tuplas é a sua escolha para qualquer cenário de classificação que envolva uma chave de classificação composta:
Como esta resposta se provou popular, gostaria de expandi-la, observando que uma solução semelhante à seguinte poderia, em algumas circunstâncias, ser considerada de nível empresarial ™:
Dado
es: SeqLike[Employee]
,es.sorted()
irá classificar por nome ees.sorted(Employee.orderingById)
irá classificar por id. Isso tem alguns benefícios:Ordering
, portanto, fornecer uma classificação elimina diretamente uma conversão implícita na maioria dos casos.fonte
value compare is not a member of (String, Int)
.Isso tem a vantagem de ser atualizado automaticamente sempre que A muda. Mas, os campos de A precisam ser colocados na ordem em que o pedido os usará.
fonte
<console>:12: error: not found: value unapply
Para resumir, existem três maneiras de fazer isso:
Defina um pedido personalizado. O benefício desta solução é que você pode reutilizar ordens e ter várias maneiras de classificar instâncias da mesma classe:
Respondendo à sua pergunta Existe alguma função padrão incluída no Scala que pode fazer mágica como List ((2,1), (1,2)).
Há um conjunto de ordenações predefinidas , por exemplo, para String, tuplas até 9 aridade e assim por diante.
Não existe tal coisa para classes de caso, uma vez que não é uma coisa fácil de rolar, dado que os nomes dos campos não são conhecidos a priori (pelo menos sem a magia das macros) e você não pode acessar os campos da classe de caso de outra forma que não nome / usando o iterador do produto.
fonte
O
unapply
método do objeto complementar fornece uma conversão de sua classe de caso para umOption[Tuple]
, em queTuple
é a tupla correspondente à primeira lista de argumentos da classe de caso. Em outras palavras:fonte
O método sortBy seria uma maneira típica de fazer isso, por exemplo (classificar no
tag
campo):fonte
l.sortBy( e => e._tag + " " + e._load + " " + ... )
?sortBy
, então sim, ou adicione / use uma função adequada para / na classe (por exemplo_.toString
, ou seu próprio método personalizado lexograficamente significativo ou função externa).List((2,1),(1,2)).sorted
para os objetos da classe de caso? Não vejo grande diferença entre tuplas nomeadas (classe de caso == tupla nomeada) e tuplas simples.Option[TupleN]
, em seguida, chamarget
em que:l.sortBy(A.unapply(_).get)foreach(println)
, que usa a ordenação fornecido na tupla correspondente, mas este é simplesmente um exemplo explícito da idéia geral eu dou acima .Já que você usou uma classe de caso, você pode estender com Ordered assim:
fonte