Using Pattern Matching for Ordered.compare in Scala

I have the following Scala class:

case class Person(firstName: String, lastName: String, age: Int) extends Ordered[Person] { def compare(that: Person): Int = { if (this.lastName < that.lastName) -1 else if (this.lastName > that.lastName) 1 else if (this.firstName < that.firstName) -1 else if (this.firstName > that.firstName) 1 else this.age compare that.age } } 

to allow sorting by lastName, firstName and age.

How can I write this using pattern matching? I came up with the following, but is there a better way?

 case class Person(firstName: String, lastName: String, age: Int) extends Ordered[Person] { def compare(that: Person): Int = { that match { case Person(_, thatLastName, _) if this.lastName < thatFile => -1 case Person(_, thatLastName, _) if this.lastName > thatFile => 1 case Person(thatFirstName, _, _) if this.firstName < thatFirstName => -1 case Person(thatFirstName, _, _) if this.firstName > thatFirstName => 1 case Person(_, _, thatAge) => this.age compare thatAge } } } 

UPDATE . Changed the use of Ordering[A] according to Landei's answer:

 implicit val personOrdering = new Ordering[Person] { def compare(first: Person, second:Person): Int = { second match { case Person(_, thatLastName, _) if first.lastName < thatLastName => -1 case Person(_, thatLastName, _) if first.lastName > thatLastName => 1 case Person(thatFirstName, _, _) if first.firstName < thatFirstName => -1 case Person(thatFirstName, _, _) if first.firstName > thatFirstName => 1 case Person(_, _, thatAge) => first.age compare thatAge } } } case class Person(firstName: String, lastName: String, age: Int) 

but it seems uncomfortable that I answer only second . How can I make it more "elegant"?

+2
source share
1 answer

The preferred way in Scala is to provide an implicit order instead of Ordered, which is much more flexible and does not give a headache regarding inheritance.

Regarding pattern matching, I don't see a better way, because the result of the comparison methods is Int s, which are not guaranteed to be -1, 0, 1. Haskell's solution for returning enum objects (LT, EQ, GT) is much cleaner and comparable with a sample, but it seems Scala followed the C ++ / Java tradition here for compatibility reasons.

Of course, you can expand your own comparison "framework":

 abstract sealed class CompResult(val toInt:Int) { def andThen(next: => CompResult): CompResult } case object LT extends CompResult(-1) { def andThen(next: => CompResult) = LT } case object EQ extends CompResult(0) { def andThen(next: => CompResult) = next } case object GT extends CompResult(1) { def andThen(next: => CompResult) = GT } implicit def int2Comp(n:Int) = if (n == 0) EQ else if (n < 0) LT else GT (("sdkfhs" compareTo "fldgkjdfl"):CompResult) match { case LT => println("less") case EQ => println("same") case GT => println("more") } 

In your case, you can write:

 case class Person(firstName: String, lastName: String, age: Int) extends Ordered[Person] { def compare(that: Person): Int = { (this.lastName compareTo that.lastName). andThen (this.firstName compareTo that.firstName). andThen (this.age compare that.age).toInt } } 
+10
source

Source: https://habr.com/ru/post/915804/


All Articles