Qual é a melhor maneira de classificar inversamente o scala?

137

Qual é a melhor maneira de fazer uma classificação inversa em scala? Eu imagino que o seguinte seja um pouco lento.

list.sortBy(_.size).reverse

Existe uma maneira conveniente de usar sortBy, mas obter uma classificação reversa? Eu preferiria não precisar usar sortWith.

schmmd
fonte
1
as soluções abaixo são muito boas, mas ainda acho a sua maneira original de fazer isso mais simples de ler. Eu verifiquei que há uma desvantagem computacional nessa maneira de escrever, como você suspeitava. O teste que fiz foi o seguinte: val clock = new Timer (1 a 1e6.toInt) .sorted (Ordenação [Int] .reverse) clock.addLap ("caminho correto") (1 a 1e6.toInt) .sorted.reverse clock.addLap ("maneira incorreta") println (clock.toString) [maneira correta, volta = 76, duração. = 76] [caminho incorreto, volta = 326, duração. = 250]
Khoa

Respostas:

241

Pode haver uma maneira óbvia de alterar o sinal, se você classificar por algum valor numérico

list.sortBy(- _.size)

De maneira mais geral, a classificação pode ser feita pelo método classificado com um Pedido implícito, que você pode tornar explícito, e o Pedido tem um reverso (não a lista abaixo). Você pode fazer

list.sorted(theOrdering.reverse)

Se a ordem que você deseja reverter for a ordem implícita, você poderá obtê-la implicitamente [Ordering [A]] (A do tipo que você está solicitando) ou melhor Ordering [A]. Isso seria

list.sorted(Ordering[TheType].reverse)

sortBy é como usar Ordering.by, para que você possa

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

Talvez não seja o mais curto para escrever (em comparação com menos), mas a intenção é clara

Atualizar

A última linha não funciona. Para aceitar o _in Ordering.by(_.size), o compilador precisa saber em qual tipo estamos solicitando, para que ele possa digitar o _. Pode parecer que esse seria o tipo do elemento da lista, mas não é assim, como é a assinatura da classificação def sorted[B >: A](ordering: Ordering[B]). A ordem pode estar ativada A, mas também em qualquer ancestral de A(você pode usar byHashCode : Ordering[Any] = Ordering.by(_.hashCode)). E, de fato, o fato de que a lista é covariante força essa assinatura. Pode-se fazer

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

mas isso é muito menos agradável.

Didier Dupont
fonte
Super útil - não tinha certeza se estava fazendo uma pergunta idiota, mas aprendi muito com sua resposta!
21411 schmmd
Exceto que isso não funciona. Eu nunca deveria responder quando não tenho o REPL à mão. Veja atualização.
Didier Dupont
E para classificar em um campo secundário, retorne uma tupla:list.sortBy(x => (-x.size, x.forTiesUseThisField))
Brent Faust
2
Em vez de list.sorted(Ordering.by((_: TheType).size).reverse)considerá- list.sorted(Ordering.by[TheType, Int](_.size).reverse)lo mais claro (mas mais longo) para o meu ponto de vista.
Cherry
5
Eu pessoalmente list.sortBy(_.size)(Ordering[Int].reverse)também gosto .
Dtech
112
list.sortBy(_.size)(Ordering[Int].reverse)
incrop
fonte
27

talvez para encurtar um pouco mais:

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

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

Fácil, fácil (pelo menos em 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
fonte
9

sortBypossui parâmetro implícito ordque fornece pedidos

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

então, podemos definir o próprio Orderingobjeto

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
fonte
9

Ambos sortWithe sortBypossuem uma sintaxe 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))

Acho o sortWithmais fácil de entender.

Jus12
fonte
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
fonte
Não aborda a questão.
tilde
1

Outra possibilidade nos casos em que você passa uma função que talvez não consiga modificar diretamente para um Arraybuffer via sortWith, por exemplo:

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
fonte
0

este é o meu código;)

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

wordCounts.sortBy(- _._2).collect()
Anxo P
fonte
1
Isso não está incorreto, mas a parte interessante (a segunda linha) é abafada pela linha desnecessária à sua frente. Basicamente, o ponto aqui é que uma maneira de fazer uma classificação inversa é negar o valor da classificação.
Carl-Eric Menzel