Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala sorting Options

Tags:

scala

If I have a case class like this

case class Foo(bar: Option[String])

why does this work

scala> val l = List(Foo(Some("b")), Foo(Some("a")), Foo(Some("c")))
l: List[Foo] = List(Foo(Some(b)), Foo(Some(a)), Foo(Some(c)))
scala> l.sortBy(_.bar)
res1: List[Foo] = List(Foo(Some(a)), Foo(Some(b)), Foo(Some(c)))

but not this

scala> l.sortWith((x,y) => x.bar > y.bar)
<console>:11: error: value > is not a member of Option[String]
          l.sortWith((x,y) => x.bar > y.bar)

If I want to sort a List of Option[String] in descending order, is it just simpler to use sortBy and then reverse the list?

like image 361
mplis Avatar asked Nov 15 '13 18:11

mplis


1 Answers

It's because sorted but not sortWith takes an implicit parameter of type Ordering, and Ordering knows about options. With sortWith, you're on your own. And with < you're also on your own.

You can access the same machinery in a clunky fashion:

l.sortWith((a,b) => Ordering[Option[String]].gt(a.bar,b.bar))

or get the nicer version with an import (but now you'll be able to compare Options anywhere based on their contents; hopefully that is what you want):

import scala.math.Ordered._
l.sortWith((a,b) => a.bar > b.bar)

The first is such a mouthful that unless you're really pressed for performance, it's easier to just .sorted.reverse.. (And if you are really pressed for performance, you'd probably be better off handling the option logic manually, e.g. a.bar.isEmpty || !b.bar.isEmpty || a.bar.get < b.bar.get.)

If you're going to do multiple sorts, it's hard to beat the second for clarity. For just one test, I'd still probably favor .sorted.reverse.

like image 51
Rex Kerr Avatar answered Oct 14 '22 16:10

Rex Kerr