What is the best way to do an inverse sort in scala? I imagine the following is somewhat slow.
list.sortBy(_.size).reverse
Is there a conveinient way of using sortBy but getting a reverse sort? I would rather not need to use sortWith
.
What is the best way to do an inverse sort in scala? I imagine the following is somewhat slow.
list.sortBy(_.size).reverse
Is there a conveinient way of using sortBy but getting a reverse sort? I would rather not need to use sortWith
.
There may be the obvious way of changing the sign, if you sort by some numeric value
list.sortBy(- _.size)
More generally, sorting may be done by method sorted with an implicit Ordering, which you may make explicit, and Ordering has a reverse (not the list reverse below) You can do
list.sorted(theOrdering.reverse)
If the ordering you want to reverse is the implicit ordering, you can get it by implicitly[Ordering[A]] (A the type you're ordering on) or better Ordering[A]. That would be
list.sorted(Ordering[TheType].reverse)
sortBy is like using Ordering.by, so you can do
list.sorted(Ordering.by(_.size).reverse)
Maybe not the shortest to write (compared to minus) but intent is clear
Update
The last line does not work. To accept the _
in Ordering.by(_.size)
, the compiler needs to know on which type we are ordering, so that it may type the _
. It may seems that would be the type of the element of the list, but this is not so, as the signature of sorted is
def sorted[B >: A](ordering: Ordering[B])
. The ordering may be on A
, but also on any ancestor of A
(you might use byHashCode : Ordering[Any] = Ordering.by(_.hashCode)
). And indeed, the fact that list is covariant forces this signature.
One can do
list.sorted(Ordering.by((_: TheType).size).reverse)
but this is much less pleasant.
Both sortWith
and sortBy
have a compact syntax:
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))
I find the one with sortWith
easier to understand.
sortBy
has implicit parameter ord
which provides ordering
def sortBy [B] (f: (A) ⇒ B)(implicit ord: Ordering[B]): List[A]
so, we can define own Ordering
object
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)
Another possibility in cases where you pass a function that you may not be able to modify directly to an Arraybuffer via sortWith for example:
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