2011-10-18 18 views
99

Jaki jest najlepszy sposób na sortowanie odwrotne w scala? Wyobrażam sobie, że poniższe jest nieco powolne.Jaki jest najlepszy sposób odwrócenia sortowania w scala?

list.sortBy(_.size).reverse 

Czy istnieje zwykły sposób użycia sortBy, ale otrzymanie sortowania odwrotnego? Wolałbym nie potrzebować używać sortWith.

+0

rozwiązania są bardzo ładne, ale ja jeszcze znaleźć swój oryginalny sposób robi to łatwiejsze do odczytania. Potwierdziłem, że istnieje podejrzenie wad obliczeniowych dla tego sposobu pisania. Test I nie jest tak: val zegara = nowy czasowy (1 do 1e6.toInt) .sorted (zamawiania [Int] .reverse) clock.addLap ("prawidłowy sposób") (1 do 1e6.toInt) .sorted.reverse clock.addLap ("niepoprawny sposób") println (clock.toString) [poprawny sposób, okrążenie = 76, dur. = 76] | [Niepoprawny sposób, okrążenie = 326, dur. = 250] – BlueSky

Odpowiedz

175

Może być oczywiste wa y zmianę znaku, w przypadku sortowania według pewnej wartości liczbowej

list.sortBy(- _.size) 

Bardziej ogólnie, sortowania mogą być wykonywane metodą sortowanych z domniemanym zamawianiu których można dokonać wyraźnego i zamawiania ma odwrotnie (nie listy reverse poniżej) można zrobić

list.sorted(theOrdering.reverse) 

przypadku zamawiania chcesz odwrócić kolejność jest niejawna, można dostać go w sposób dorozumiany [zamawiania [A]] (A typem jesteś zamawiania on) lub lepiej Zamawianie [A]. To byłoby

list.sorted(Ordering[TheType].reverse) 

SortBy jest jak używanie Ordering.by, więc można zrobić

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

Może najkrótsza napisać (w porównaniu do minus), ale intencja jest jasna

Aktualizacja

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

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

ale jest to znacznie mniej przyjemne.

+0

Super pomocny - nie byłem pewien, czy zadaję głupie pytanie, ale wiele nauczyłem się z twojej odpowiedzi! – schmmd

+0

Poza tym, że nie działa. Nigdy nie powinienem odpowiadać, gdy nie mam pod ręką REPL. Zobacz aktualizację. –

+0

Aby sortować na drugim polu, należy zwrócić krotkę: 'list.sortBy (x => (-x.size, x.forTiesUseThisField))' –

7

sortBy ma parametr niejawny ord który zapewnia nakazujący

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

tak, możemy zdefiniować własne Ordering obiektowi

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

Łatwa 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) 
81
list.sortBy(_.size)(Ordering[Int].reverse) 
23

może by go skrócić trochę więcej:

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

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

Inną możliwością w przypadkach, gdy przechodzą funkcję, która może nie być w stanie modyfikować bezpośrednio do Arraybuffer poprzez 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 
6
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) 
2

Zarówno sortWith i sortBy mieć 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 z sortWith jest łatwiejszy do zrozumienia.

0

to jest mój kod;)

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

wordCounts.sortBy (- _._ 2) .collect() poniżej

+0

To nie jest niepoprawne, ale interesująca część (druga linia) jest zagłuszana przez niepotrzebną linię przed nią. Zasadniczo chodzi o to, że jednym ze sposobów na sortowanie odwrotne jest zanegowanie wartości sortowania. –

Powiązane problemy