Який найкращий спосіб інверсувати сортування в масштабі?


137

Який найкращий спосіб зробити зворотний сорт в масштабі? Я думаю, що наступне дещо повільне.

list.sortBy(_.size).reverse

Чи є сприятливий спосіб використання sortBy, але отримання зворотного сортування? Я б скоріше не потребував використання sortWith.


1
рішення нижче є дуже приємними, але я все ще вважаю ваш оригінальний спосіб зробити це простішим для читання. Я переконався, що в такому способі письма є обчислювальний недолік, як ви підозрювали. Тест, який я зробив, виглядає так: val clock = новий таймер (від 1 до 1e6.toInt). Вказаний (замовлення [Int]. Зворотний) clock.addLap ("правильний спосіб") (від 1 до 1e6.toInt) .sorted.reverse clock.addLap ("неправильний шлях") println (clock.toString) [правильний шлях, пробіг = 76, dur. = 76] | [неправильний шлях, коліно = 326, дур. = 250]
Хоа

Відповіді:


242

Можливо, існує очевидний спосіб зміни знаку, якщо сортувати за деяким числовим значенням

list.sortBy(- _.size)

Більш загально, сортування може бути здійснено методом, відсортованим із неявним впорядкуванням, який ви можете зробити явним, а впорядкування має зворотний (не перелік зворотного списку нижче) Ви можете зробити

list.sorted(theOrdering.reverse)

Якщо замовлення, яке ви хочете змінити, - це неявне впорядкування, ви можете отримати його неявно [Ordering [A]] (тип, який ви замовляєте) або краще Ordering [A]. Це було б

list.sorted(Ordering[TheType].reverse)

sortBy - це як використовувати Ordering.by, так що ви можете це зробити

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

Можливо, не найкоротше написати (порівняно з мінусом), але намір зрозумілий

Оновлення

Останній рядок не працює. Для того, щоб прийняти _в систему Ordering.by(_.size), потреби компілятора , щоб знати , на який тип ми впорядкованість, так що він може введіть _. Може здатися, що це був би тип елемента списку, але це не так, як сортується підпис def sorted[B >: A](ordering: Ordering[B]). Замовлення може бути ввімкнено A, але також і для будь-якого предка A(ви можете використовувати byHashCode : Ordering[Any] = Ordering.by(_.hashCode)). І справді, той факт, що список є коваріантним, змушує цей підпис. Можна зробити

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

але це набагато менш приємно.


Супер корисно - я не був впевнений, чи задавав я німецьке запитання, але я дізнався багато з вашої відповіді!
schmmd

За винятком того, що це не працює. Я ніколи не повинен відповідати, коли мені не підходить REPL. Дивіться оновлення.
Дідьє Дюпон

І щоб сортувати по другому полю, поверніть кортеж:list.sortBy(x => (-x.size, x.forTiesUseThisField))
Brent Faust

2
Замість того, щоб list.sorted(Ordering.by((_: TheType).size).reverse)вважати list.sorted(Ordering.by[TheType, Int](_.size).reverse)це більш зрозумілим (але довше) для моєї точки зору.
Вишня

5
Мені особисто list.sortBy(_.size)(Ordering[Int].reverse)теж подобається .
dtech


27

можливо, щоб трохи скоротити це:

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

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

19

Легкий горошок (принаймні у випадку 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

sortByмає неявний параметр, ordякий забезпечує впорядкування

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

Отже, ми можемо визначити власний Orderingоб’єкт

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

Обидва sortWithі sortByмають компактний синтаксис:

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

Мені здається, що sortWithлегше зрозуміти.



1

Інша можливість у випадках, коли ви передаєте функцію, яку ви, можливо, не зможете змінити безпосередньо до Arraybuffer через sortWith:

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

це мій код;)

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

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

1
Це невірно, але цікава частина (другий рядок) заглушена непотрібною лінією перед нею. По суті, справа в тому, що один із способів зробити зворотний сортування - це заперечення значення сортування.
Карл-Ерік Менцель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.