¿Cuál es la mejor forma de ordenar inversa en scala?

137

¿Cuál es la mejor manera de hacer una ordenación inversa en scala? Me imagino que lo siguiente es algo lento.

list.sortBy(_.size).reverse

¿Hay una manera conveniente de usar sortBy pero obteniendo una clasificación inversa? Prefiero no necesitar usar sortWith.

schmmd
fuente
1
Las soluciones a continuación son muy buenas, pero aún encuentro su forma original de hacer esto más simple de leer. Verifiqué que hay un inconveniente computacional en esta forma de escritura, como sospechabas. La prueba que hice es la siguiente: val clock = new Timer (1 to 1e6.toInt) .sorted (Ordering [Int] .reverse) clock.addLap ("forma correcta") (1 to 1e6.toInt) .sorted.reverse clock.addLap ("forma incorrecta") println (clock.toString) [forma correcta, lap = 76, dur. = 76] | [forma incorrecta, vuelta = 326, dur. = 250]
Khoa

Respuestas:

241

Puede haber una forma obvia de cambiar el signo, si ordena por algún valor numérico

list.sortBy(- _.size)

En términos más generales, la ordenación se puede realizar por un método ordenado con un ordenamiento implícito, que puede hacer explícito, y el ordenamiento tiene un reverso (no el reverso de la lista a continuación).

list.sorted(theOrdering.reverse)

Si el orden que desea revertir es el ordenamiento implícito, puede obtenerlo implícitamente [Ordenar [A]] (A del tipo que está ordenando) o mejor Ordenar [A]. Eso sería

list.sorted(Ordering[TheType].reverse)

sortBy es como usar Ordering.by, por lo que puedes hacer

list.sorted(Ordering.by(_.size).reverse)

Quizás no sea el más corto de escribir (en comparación con menos) pero la intención es clara

Actualizar

La última línea no funciona. Para aceptar el _in Ordering.by(_.size), el compilador necesita saber en qué tipo estamos ordenando, para que pueda escribir el _. Puede parecer que ese sería el tipo de elemento de la lista, pero esto no es así, como lo es la firma de ordenado def sorted[B >: A](ordering: Ordering[B]). El pedido puede estar activado A, pero también en cualquier antecesor de A(puede usar byHashCode : Ordering[Any] = Ordering.by(_.hashCode)). Y, de hecho, el hecho de que la lista es covariante obliga a esta firma. Uno puede hacer

list.sorted(Ordering.by((_: TheType).size).reverse)

Pero esto es mucho menos agradable.

Didier Dupont
fuente
Súper útil: no estaba seguro de si estaba haciendo una pregunta tonta, ¡pero aprendí mucho de tu respuesta!
schmmd
Excepto que no funciona. Nunca debería responder cuando no tengo REPL a mano. Ver actualización.
Didier Dupont
Y para ordenar en un campo secundario, devuelve una tupla:list.sortBy(x => (-x.size, x.forTiesUseThisField))
Brent Faust
2
En lugar de list.sorted(Ordering.by((_: TheType).size).reverse)considerarlo list.sorted(Ordering.by[TheType, Int](_.size).reverse)más claro (pero más largo) para mi punto de vista.
Cereza
55
Personalmente list.sortBy(_.size)(Ordering[Int].reverse)también me gusta .
dtech
112
list.sortBy(_.size)(Ordering[Int].reverse)
incrop
fuente
27

quizás para acortarlo un poco más:

def Desc[T : Ordering] = implicitly[Ordering[T]].reverse

List("1","22","4444","333").sortBy( _.size )(Desc)
Bruno Bieth
fuente
19

Fácil guisante (al menos en caso de size):

scala> val list = List("abc","a","abcde")
list: List[java.lang.String] = List(abc, a, abcde)

scala> list.sortBy(-_.size)
res0: List[java.lang.String] = List(abcde, abc, a)

scala> list.sortBy(_.size)
res1: List[java.lang.String] = List(a, abc, abcde)
Om nom nom
fuente
9

sortBytiene un parámetro implícito ordque proporciona orden

def sortBy [B] (f: (A) ⇒ B)(implicit ord: Ordering[B]): List[A]

entonces, podemos definir un Orderingobjeto propio

scala> implicit object Comp extends Ordering[Int] {
 | override def compare (x: Int, y: Int): Int = y - x
 | }
defined module Comp

List(3,2,5,1,6).sortBy(x => x)
res5: List[Int] = List(6, 5, 3, 2, 1)
4e6
fuente
9

Ambos sortWithy sortBytienen una sintaxis compacta:

case class Foo(time:Long, str:String)

val l = List(Foo(1, "hi"), Foo(2, "a"), Foo(3, "X"))

l.sortWith(_.time > _.time)  // List(Foo(3,X), Foo(2,a), Foo(1,hi))

l.sortBy(- _.time)           // List(Foo(3,X), Foo(2,a), Foo(1,hi))

l.sortBy(_.time)             // List(Foo(1,hi), Foo(2,a), Foo(3,X))

Encuentro el que es sortWithmás fácil de entender.

Jus12
fuente
8
val list = List(2, 5, 3, 1)
list.sortWith(_>_) -> res14: List[Int] = List(5, 3, 2, 1)
list.sortWith(_<_) -> res14: List[Int] = List(1, 2, 3, 5)
Tomek Kozlowski
fuente
No aborda la pregunta.
tilde
1

Otra posibilidad en los casos en que pasa una función que no puede modificar directamente a un Arraybuffer mediante sortWith, por ejemplo:

val buf = collection.mutable.ArrayBuffer[Int]()
buf += 3
buf += 9
buf += 1

// the sort function (may be passed through from elsewhere)
def sortFn = (A:Int, B:Int) => { A < B }

// the two ways to sort below
buf.sortWith(sortFn)                        // 1, 3, 9
buf.sortWith((A,B) => { ! sortFn(A,B) })    // 9, 3, 1
Chris
fuente
0

este es mi código;)

val wordCounts = logData.flatMap(line => line.split(" "))
                        .map(word => (word, 1))
                        .reduceByKey((a, b) => a + b)

wordCounts.sortBy(- _._2).collect()
Anxo P
fuente
1
Esto no es incorrecto, pero la parte interesante (la segunda línea) queda ahogada por la línea innecesaria que tiene delante. Básicamente, el punto aquí es que una forma de hacer una ordenación inversa es negar el valor de ordenación.
Carl-Eric Menzel