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