This question is probably quite dumb, but I can't find an example and can't figure it out.
I want to compare two Person classes by last, first, and middle name, in that order. Here's the brain-dead way to do it:
def compare(that: Person): Int = {
val last: Int = lastName.compare(that.lastName)
if (last != 0) last
else {
val first: Int = firstName.compare(that.firstName)
if (first != 0) first
else middleName.compare(that.middleName)
}
I know there's some much more clever way to do this (probably using Ordering) but I can't put my finger on it.
Todd
I figured out this once I realized how to access the right things in Ordering.
def compare(that: Person): Int = {
Ordering.Tuple3(Ordering.String, Ordering.String, Ordering.String).compare(
(lastName, firstName, middleName),
(that.lastName, that.firstName, that.middleName))
}
I'm pretty sure I can get away with fewer explicits, but this works and is reasonably compact.
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
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) }
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
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 love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With