Qual è il modo migliore per invertire l'ordinamento in scala?


137

Qual è il modo migliore per fare un ordinamento inverso in scala? Immagino che il seguente sia un po 'lento.

list.sortBy(_.size).reverse

Esiste un modo conveniente di usare sortBy ma ottenere un ordinamento inverso? Preferirei non aver bisogno di usare sortWith.


1
le soluzioni di seguito sono tutte molto belle ma trovo ancora il tuo modo originale di farlo più semplice da leggere. Ho verificato che esiste un inconveniente computazionale in questo modo di scrivere, come sospettavi. Il test che ho fatto è il seguente: val clock = new Timer (da 1 a 1e6.toInt) .sorted (Ordering [Int] .reverse) clock.addLap ("modo corretto") (da 1 a 1e6.toInt) .sorted.reverse clock.addLap ("modo errato") println (clock.toString) [modo corretto, giro = 76, dur. = 76] | [modo errato, giro = 326, dur. = 250]
Khoa

Risposte:


242

Potrebbe esserci il modo ovvio di cambiare il segno, se si ordina in base a un valore numerico

list.sortBy(- _.size)

Più in generale, l'ordinamento può essere eseguito con il metodo ordinato con un ordinamento implicito, che è possibile rendere esplicito, e l'ordinamento ha un rovescio (non l'elenco rovesciato di seguito).

list.sorted(theOrdering.reverse)

Se l'ordinamento che si desidera invertire è l'ordinamento implicito, è possibile ottenerlo implicitamente [Ordine [A]] (A il tipo su cui si sta ordinando) o Ordine migliore [A]. Sarebbe

list.sorted(Ordering[TheType].reverse)

sortBy è come usare Ordering.by, quindi puoi farlo

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

Forse non è il più breve da scrivere (rispetto al meno) ma l'intento è chiaro

Aggiornare

L'ultima riga non funziona. Per accettare _in Ordering.by(_.size), il compilatore deve sapere su quale tipo stiamo ordinando, in modo che possa digitare _. Potrebbe sembrare che sarebbe il tipo di elemento dell'elenco, ma non è così, come lo è la firma di ordinati def sorted[B >: A](ordering: Ordering[B]). L'ordinamento può essere attivo A, ma anche su qualsiasi antenato di A(è possibile utilizzare byHashCode : Ordering[Any] = Ordering.by(_.hashCode)). E infatti, il fatto che l'elenco sia covariante forza questa firma. Uno può fare

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

ma questo è molto meno piacevole.


Super utile - Non ero sicuro di porre una domanda stupida, ma ho imparato molto dalla tua risposta!
schmmd

Solo che non funziona. Non dovrei mai rispondere quando non ho REPL a portata di mano. Vedi aggiornamento
Didier Dupont,

E per ordinare su un campo secondario, restituisci una tupla:list.sortBy(x => (-x.size, x.forTiesUseThisField))
Brent Faust,

2
Invece di list.sorted(Ordering.by((_: TheType).size).reverse)considerarlo list.sorted(Ordering.by[TheType, Int](_.size).reverse)più chiaro (ma più lungo) per il mio punto di vista.
Cherry,

5
Personalmente mi piace list.sortBy(_.size)(Ordering[Int].reverse)anche.
dtech,

112
list.sortBy(_.size)(Ordering[Int].reverse)

27

forse per accorciarlo un po 'di più:

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

List("1","22","4444","333").sortBy( _.size )(Desc)

19

Facile peasy (almeno in caso di 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)

9

sortByha un parametro implicito ordche fornisce l'ordinamento

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

quindi, possiamo definire il proprio Orderingoggetto

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)

9

Entrambi sortWithe sortByhanno una sintassi compatta:

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))

Trovo quello con sortWithpiù facile da capire.


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)

Non affronta la domanda.
tilde

1

Un'altra possibilità nei casi in cui si passa una funzione che potrebbe non essere possibile modificare direttamente in un array Array tramite sortWith ad esempio:

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

0

questo è il mio codice;)

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

wordCounts.sortBy(- _._2).collect()

1
Ciò non è errato, ma la parte interessante (la seconda riga) viene eliminata dalla riga non necessaria prima di essa. Fondamentalmente, il punto qui è che un modo per fare un ordinamento inverso è quello di negare il valore dell'ordinamento.
Carl-Eric Menzel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.