定义了扩展Ordering [A]的A类和A的子类B,如何自动对B数组进行排序? Scala编译器抱怨它“找不到参数ord的隐含值:Ordering [B]”。这是一个具体的REPL示例(Scala 2.8),其中A =得分,B = CommentedScore:
class Score(val value: Double) extends Ordered[Score] {
def compare(that: Score) = value.compare(that.value)
}
defined class Score
trait Comment { def comment: String }
defined trait Comment
class CommentedScore(value: Double, val comment: String) extends Score(value) with Comment
defined class CommentedScore
val s = new CommentedScore(10,"great")
s: CommentedScore = CommentedScore@842f23
val t = new CommentedScore(0,"mediocre")
t: CommentedScore = CommentedScore@dc2bbe
val commentedScores = Array(s,t)
commentedScores: Array[CommentedScore] = Array(CommentedScore@b3f01d, CommentedScore@4f3c89)
util.Sorting.quickSort(commentedScores)
error: could not find implicit value for parameter ord: Ordering[CommentedScore]
util.Sorting.quickSort(commentedScores)
^
如何解决这个问题(即,免费对Array [B] = Array [CommentedScore]进行排序“,假设我知道如何对Array [A] = Array [Score]进行排序),以优雅的方式这避免了样板?
谢谢!
答案 0 :(得分:3)
自己添加所需的隐式:
implicit val csOrd: Ordering[CommentedScore] = Ordering.by(_.value)
您可以将其放在CommentedScore
随播广告对象中,以便在使用网站上没有样板。
编辑:如果您希望仅在继承树的顶部定义排序方法,您仍然必须为每个子类提供Ordering
,但您可以定义compare
方法根据{{1}}对象中的Ordering
Score
。即。
object Score {
implicit val ord: Ordering[Score] = Ordering.by(_.value)
}
object CommentedScore {
implicit val csOrd = new Ordering[CommentedScore] {
def compare(x: CommentedScore, y: CommentedScore) = Score.ord.compare(x, y)
}
}
如果您不想为每个子类重新定义它,可以使用通用方法生成Ordering
:
object Score {
implicit def ord[T <: Score]: Ordering[T] = Ordering.by(_.value)
}
由于def
而不是val
,效率稍低,每次需要时都会创建一个新的Ordering
。然而,开销很小。另请注意,现在我们没有Ordered
特征和compare
方法Ordering
。
答案 1 :(得分:2)
您可以使用scalaz中的Order
,它是逆变的,因此您无需为每个子类定义它。这是一个例子:
import scalaz._
import Scalaz._
class Score(val value: Double)
object Score {
implicit val scoreOrd: Order[Score] = orderBy(_.value)
}
trait Comment { def comment: String }
class CommentedScore(value: Double, val comment: String) extends Score(value) with Comment {
override def toString = s"cs($value, $comment)"
}
def quickSort[E: Order](list: List[E]): List[E] = list match {
case Nil => Nil
case head :: tail =>
val (less, more) = tail partition { e => implicitly[Order[E]].order(e, head) == LT }
quickSort(less) ::: head :: quickSort(more)
}
println(quickSort(List(
new CommentedScore(10,"great"),
new CommentedScore(5,"ok"),
new CommentedScore(8,"nice"),
new CommentedScore(0,"mediocre")
))) // List(cs(0.0, mediocre), cs(5.0, ok), cs(8.0, nice), cs(10.0, great))
答案 2 :(得分:1)
这有效:
val scoreArray: Array[Score] = Array(s, t)
util.Sorting.quickSort(scoreArray)
或者,如果您从Array[CommentedScore]
开始:
val scoreArray: Array[Score] = commentedScores.map(identity)
util.Sorting.quickSort(scoreArray)
请注意,您可以使用以下方式进行更简单的排序:
scoreArray.sorted