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.


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.


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


27

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

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

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

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)

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)

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.


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)

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

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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.