4

Ordering[A] を拡張するクラス A と A のサブクラス B を定義した後、B の配列を自動的にソートするにはどうすればよいでしょうか? Scala コンパイラーは、「パラメーター ord: Ordering[B] の暗黙的な値が見つかりませんでした」と文句を言います。A = Score および B = CommentedScore の具体的な REPL の例 (Scala 2.8) を次に示します。

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] をソートする方法を知っている場合)。 ?

ありがとう!

4

3 に答える 3

3

必要な暗黙的な自分を追加します。

implicit val csOrd: Ordering[CommentedScore] = Ordering.by(_.value)

CommentedScoreuse-site にボイラープレートがないように、これをコンパニオン オブジェクトに入れることができます。


編集:順序付けメソッドを継承ツリーの最上位でのみ定義する場合は、Orderingサブクラスごとに for を提供する必要がありますが、オブジェクト内のcompareメソッドに関してメソッドを定義できます。すなわちOrderingScore

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

于 2012-08-29T05:29:24.880 に答える
2

反変である from 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))
于 2012-08-29T07:54:32.910 に答える
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
于 2012-08-29T05:14:31.323 に答える