Scala Ordered by multiple fields

Option 1: sortBy

Using the sortBy method, this can be pretty simple:

case class Person(first: String, middle: String, last: String)
val personList = List(Person("john", "a", "smith"), Person("steve", "x", "scott"), Person("bill", "w", "smith"))
personList.sortBy{ case Person(f,m,l) => (l,f,m) } 

Option 2: Extend Ordered[Person]

By extending Ordered[Person], the class will know how to sort itself, so we get things like sorted, min, and max for free:

case class Person(first: String, middle: String, last: String) extends Ordered[Person] {
  def compare(that: Person): Int =
    (last compare that.last) match {
      case 0 => 
        (first compare that.first) match {
          case 0 => middle compare that.middle
          case c => c
        }
      case c => c
    }
}

val personList = List(Person("john", "a", "smith"), Person("steve", "x", "scott"), Person("bill", "w", "smith"))
personList.sorted
personList.min
personList.max

Option 3: Implicit Ordering

If you use an implicit Ordering, then you get sorted, min, etc without having that particular ordering tied to your original class. This decoupling might be convenient, or it might by annoying, depending on your specific case.

case class Person(first: String, middle: String, last: String)

implicit val ord = new Ordering[Person] { 
  def compare(self: Person, that: Person): Int =
    (self.last compare that.last) match {
      case 0 => 
        (self.first compare that.first) match {
          case 0 => self.middle compare that.middle
          case c => c
        }
      case c => c
    }
}

val personList = List(Person("john", "a", "smith"), Person("steve", "x", "scott"), Person("bill", "w", "smith"))
personList.sorted
personList.min
personList.max

If you are using scala 2.13+ you can use Ordering.by and orElseBy. It is quite explicit.

case class Person(first: String, middle: String, last: String)

implicit val ordering: Ordering[Person] = Ordering.by[Person, String](_.first)
   .orElseBy(_.middle)
   .orElseBy(_.last)

val list = List(Person("john", "a", "smith"), Person("steve", "x", "scott"), Person("bill", "w", "smith"))

list.sorted

Tags:

Scala