scala - español - falsos cognados en ingles pdf
forma fácil de definir Idiomática para una clase de caso simple (6)
Como usaste una clase de caso, puedes extenderla con Ordenado como tal:
case class A(tag:String, load:Int) extends Ordered[A] {
def compare( a:A ) = tag.compareTo(a.tag)
}
val ls = List( A("words",50), A("article",2), A("lines",7) )
ls.sorted
Tengo una lista de instancias simples de la clase scala case y quiero imprimirlas en orden lexicográfico predecible usando list.sorted
, pero recibo "No orden implícito definido para ...".
¿Existe un implícito que proporciona ordenamiento lexicográfico para las clases de casos?
¿Existe una forma idiomática simple de mezclar el ordenamiento lexicográfico con la clase 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)
^
No estoy contento con un ''hack'':
scala> l.map(_.toString).sorted.foreach(println)
A(article,2)
A(lines,7)
A(words,50)
El método de aplicación del objeto complementario proporciona una conversión de su clase de caso a una Option[Tuple]
, donde Tuple
es la tupla correspondiente a la primera lista de argumentos de la clase de caso. En otras palabras:
case class Person(name : String, age : Int, email : String)
def sortPeople(people : List[Person]) =
people.sortBy(Person.unapply)
El método sortBy sería una forma típica de hacerlo, p. Ej. (Ordenar en campo de tag
):
scala> l.sortBy(_.tag)foreach(println)
A(article,2)
A(lines,7)
A(words,50)
Mi método favorito personal es utilizar el orden implícito proporcionado para Tuples, ya que es claro, conciso y correcto:
case class A(tag: String, load: Int) extends Ordered[A] {
// Required as of Scala 2.11 for reasons unknown - the companion to Ordered
// should already be in implicit scope
import scala.math.Ordered.orderingToOrdered
def compare(that: A): Int = (this.tag, this.load) compare (that.tag, that.load)
}
Esto funciona porque el acompañante de Ordered
define una conversión implícita de Ordering[T]
a Ordered[T]
que está en el alcance de cualquier clase que implemente Ordered
. La existencia de TupleN[...]
implícitas s para Tuple
s permite una conversión de TupleN[...]
a Ordered[TupleN[...]]
siempre que exista un orden implícito Ordering[TN]
para todos los elementos T1, ..., TN
de la tupla , que siempre debería ser el caso, ya que no tiene sentido ordenar en un tipo de datos sin Ordering
.
El orden implícito para Tuples es su opción para cualquier escenario de clasificación que implique una clave de clasificación compuesta:
as.sortBy(a => (a.tag, a.load))
Como esta respuesta ha demostrado ser popular, me gustaría ampliarla, y he señalado que una solución que se asemeje a lo siguiente podría considerarse, en algunas circunstancias, como grado empresarial ™:
case class Employee(id: Int, firstName: String, lastName: String)
object Employee {
// Note that because `Ordering[A]` is not contravariant, the declaration
// must be type-parametrized in the event that you want the implicit
// ordering to apply to subclasses of `Employee`.
implicit def orderingByName[A <: Employee]: Ordering[A] =
Ordering.by(e => (e.lastName, e.firstName))
val orderingById: Ordering[Employee] = Ordering.by(e => e.id)
}
Dada es: SeqLike[Employee]
, es.sorted()
ordenará por nombre, y es.sorted(Employee.orderingById)
ordenará por id. Esto tiene algunos beneficios:
- Los géneros se definen en una sola ubicación como artefactos de código visibles. Esto es útil si tiene géneros complejos en muchos campos.
- La mayoría de las funcionalidades de clasificación implementadas en la biblioteca scala operan usando instancias de
Ordering
, por lo que proporcionar un ordenamiento elimina directamente una conversión implícita en la mayoría de los casos.
Para resumir, hay tres formas de hacer esto:
- Para una clasificación única, use el método .sortBy, como @Shadowlands ha mostrado
- Para reutilizar la ordenación de la clase de caso de extensión con el rasgo Ordenado, como dijo @Keith.
Definir un pedido personalizado. El beneficio de esta solución es que puede reutilizar ordenamientos y tener varias formas de ordenar instancias de la misma clase:
case class A(tag:String, load:Int) object A { val lexicographicalOrdering = Ordering.by { foo: A => foo.tag } val loadOrdering = Ordering.by { foo: A => foo.load } } implicit val ord = A.lexicographicalOrdering val l = List(A("words",1), A("article",2), A("lines",3)).sorted // List(A(article,2), A(lines,3), A(words,1)) // now in some other scope implicit val ord = A.loadOrdering val l = List(A("words",1), A("article",2), A("lines",3)).sorted // List(A(words,1), A(article,2), A(lines,3))
Respondiendo a su pregunta ¿Hay alguna función estándar incluida en el Scala que pueda hacer magia como List ((2,1), (1,2))?
Hay un conjunto de ordenamientos predefinidos , por ejemplo, para String, tuplas de hasta 9 arity, etc.
No existe tal cosa para las clases de casos, ya que no es fácil de implementar, dado que los nombres de campo no son conocidos a priori (al menos sin magia de macros) y no se puede acceder a los campos de clase de caso de una manera que no sea nombre / uso del iterador del producto.
object A {
implicit val ord = Ordering.by(unapply)
}
Esto tiene la ventaja de que se actualiza automáticamente cada vez que cambia A. Pero, los campos de A deben colocarse en el orden en que los ordenará.