Как лучше всего использовать обратную сортировку в scala?


142

Как лучше всего выполнить обратную сортировку в scala? Я полагаю, что следующее происходит несколько медленно.

list.sortBy(_.size).reverse

Есть ли удобный способ использовать sortBy, но получить обратную сортировку? Я бы предпочел не использовать sortWith.


1
все приведенные ниже решения очень хороши, но я все же считаю, что ваш оригинальный способ сделать это проще для чтения. Я убедился, что у этого способа записи есть вычислительный недостаток, как вы и подозревали. Я провел следующий тест: val clock = new Timer (от 1 до 1e6.toInt) .sorted (Ordering [Int] .reverse) clock.addLap ("правильный путь") (от 1 до 1e6.toInt) .sorted.reverse clock.addLap («неверный способ») println (clock.toString) [правильный способ, круг = 76, длит. = 76] | [неверно, круг = 326, длит. = 250]
Khoa

Ответы:


247

Может быть очевидный способ изменить знак, если отсортировать по некоторому числовому значению

list.sortBy(- _.size)

В более общем плане сортировка может выполняться методом, отсортированным с помощью неявного упорядочивания, которое вы можете сделать явным, а упорядочение имеет обратный порядок (не обратный список ниже).

list.sorted(theOrdering.reverse)

Если порядок, который вы хотите изменить, является неявным порядком, вы можете получить его неявно [Порядок [A]] (A тип, который вы заказываете) или, лучше, Порядок [A]. Это было бы

list.sorted(Ordering[TheType].reverse)

sortBy похож на использование Ordering.by, поэтому вы можете

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

Может быть, не самый короткий для написания (по сравнению с минусом), но намерение ясное

Обновить

Последняя строчка не работает. Чтобы принять _in Ordering.by(_.size), компилятор должен знать, какой тип мы заказываем, чтобы он мог ввести _. Может показаться, что это будет тип элемента списка, но это не так, как подпись sorted 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))
Брент Фауст

2
Вместо того, чтобы list.sorted(Ordering.by((_: TheType).size).reverse)считать list.sorted(Ordering.by[TheType, Int](_.size).reverse)это более ясным (но более длинным) для моей точки зрения.
Cherry

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)

10

Оба 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легче понять.


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)


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.