在Scala中使用Ordered.compare的模式匹配

时间:2011-04-19 11:23:11

标签: scala pattern-matching

我有以下Scala类:

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
  }
}

允许按lastName,firstName和age进行排序。

如何使用模式匹配来编写?我想出了以下内容,但还有更好的方法吗?

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
    }
  }
}

更新:根据Landei的回答更改为使用Ordering[A]

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)

但我只匹配second似乎很尴尬。我怎样才能让它更“优雅”?

1 个答案:

答案 0 :(得分:10)

Scala中的首选方法是提供一个隐式的Ordering而不是Ordered,它更加灵活,并且不会给继承带来麻烦。

关于模式匹配,我认为没有更好的方法,因为比较方法的结果是Int s,不保证是-1,0,1。Haskell的回复“enum”对象的解决方案(LT,EQ,GT)更清晰,模式匹配,但出于兼容性原因,Scala似乎遵循C ++ / Java传统。

当然你可以推出自己的比较“框架”:

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")
}

在你的情况下你可以写:

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
  }
}