Jaki jest najlepszy sposób sortowania odwrotnego w scali?

137

Jaki jest najlepszy sposób sortowania odwrotnego w scali? Wyobrażam sobie, że poniższe czynności są nieco powolne.

list.sortBy(_.size).reverse

Czy istnieje wygodny sposób użycia sortBy, ale uzyskanie sortowania odwrotnego? Wolałbym nie używać sortWith.

schmmd
źródło
1
wszystkie poniższe rozwiązania są bardzo ładne, ale nadal uważam, że Twój oryginalny sposób jest prostszy do przeczytania. Sprawdziłem, jak podejrzewasz, że ten sposób pisania ma wadę obliczeniową. Test, który przeprowadziłem, wyglądał następująco: val clock = new Timer (1 do 1e6.toInt) .sorted (Ordering [Int] .reverse) clock.addLap ("right way") (1 do 1e6.toInt) .sorted.reverse clock.addLap ("nieprawidłowy sposób") println (clock.toString) [poprawny sposób, lap = 76, dur. = 76] | [nieprawidłowa droga, okrążenie = 326, czas trwania. = 250]
Khoa

Odpowiedzi:

242

Może istnieć oczywisty sposób zmiany znaku, jeśli posortujesz według wartości liczbowej

list.sortBy(- _.size)

Mówiąc bardziej ogólnie, sortowanie można przeprowadzić metodą posortowaną z niejawnym porządkiem, który można jawnie określić, a kolejność ma odwrotność (nie odwrócenie listy poniżej).

list.sorted(theOrdering.reverse)

Jeśli kolejność, którą chcesz odwrócić, jest niejawną kolejnością, możesz ją uzyskać, niejawnie [Porządkowanie [A]] (A typ, na którym zamawiasz) lub lepiej Zamawianie [A]. To byłoby

list.sorted(Ordering[TheType].reverse)

sortBy przypomina korzystanie z Ordering.by, więc możesz to zrobić

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

Może nie najkrócej (w porównaniu z minusem), ale zamiar jest jasny

Aktualizacja

Ostatnia linia nie działa. Aby zaakceptować _in Ordering.by(_.size), kompilator musi wiedzieć, na jaki typ zamawiamy, aby mógł wpisać _. Może się wydawać, że to byłby typ elementu listy, ale tak nie jest, jak podpis posortowanego def sorted[B >: A](ordering: Ordering[B]). Porządkowanie może być włączone A, ale także u każdego przodka A(możesz użyć byHashCode : Ordering[Any] = Ordering.by(_.hashCode)). I rzeczywiście, fakt, że lista jest kowariantna, wymusza ten podpis. Można to zrobić

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

ale to jest o wiele mniej przyjemne.

Didier Dupont
źródło
Super pomocny - nie byłem pewien, czy zadaję głupie pytanie, ale wiele się nauczyłem z Twojej odpowiedzi!
schmmd
Tyle że to nie działa. Nigdy nie powinienem odpowiadać, gdy nie mam pod ręką REPL. Zobacz aktualizację.
Didier Dupont
Aby posortować według drugorzędnego pola, zwróć krotkę:list.sortBy(x => (-x.size, x.forTiesUseThisField))
Brent Faust
2
Zamiast list.sorted(Ordering.by((_: TheType).size).reverse)uważać list.sorted(Ordering.by[TheType, Int](_.size).reverse)to za jaśniejsze (ale dłuższe) z mojego punktu widzenia.
Cherry
5
Osobiście list.sortBy(_.size)(Ordering[Int].reverse)też lubię .
dtech
112
list.sortBy(_.size)(Ordering[Int].reverse)
incrop
źródło
27

może skrócić to trochę bardziej:

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

List("1","22","4444","333").sortBy( _.size )(Desc)
Bruno Bieth
źródło
19

Łatwe peasy (przynajmniej w przypadku 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)
mniam mniam mniam
źródło
9

sortByma niejawny parametr, ordktóry zapewnia porządkowanie

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

więc możemy zdefiniować własny Orderingobiekt

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
źródło
9

Oba sortWithi sortBymają zwartą składnię:

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

Uważam, że ten jest sortWithłatwiejszy do zrozumienia.

Jus12
źródło
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 Kozłowski
źródło
Nie odpowiada na pytanie.
tylda
1

Inna możliwość w przypadkach, gdy przekazujesz funkcję, której możesz nie być w stanie zmodyfikować bezpośrednio do bufora tablicy przez sortWith, na przykład:

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
źródło
0

to jest mój kod;)

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

wordCounts.sortBy(- _._2).collect()
Anxo P.
źródło
1
Nie jest to błędne, ale interesująca część (druga linia) jest zagłuszana przez niepotrzebną linię przed nią. Zasadniczo chodzi o to, że jednym ze sposobów sortowania odwrotnego jest zanegowanie wartości sortowania.
Carl-Eric Menzel