1. ホーム
  2. scala

[解決済み] 単純な case class の順序を定義する簡単な慣用的方法

2022-09-07 07:46:54

質問

scala の単純な case クラスのインスタンスのリストがあり、それらを予測可能な辞書順の順序で list.sorted を使用して、予測可能な辞書順で印刷したいのですが、 "No implicit Ordering defined for ..." と表示されます。

ケースクラスの辞書的順序付けを提供する暗黙の了解は存在しますか?

辞書式順序をケースクラスに混ぜる簡単な慣用句はありますか?

scala> case class A(tag:String, load:Int)
scala> val l = List(A("words",50),A("article",2),A("lines",7))

scala> l.sorted.foreach(println)
<console>:11: error: No implicit Ordering defined for A.
          l.sorted.foreach(println)
            ^

ハック」では満足できない。

scala> l.map(_.toString).sorted.foreach(println)
A(article,2)
A(lines,7)
A(words,50)

どのように解決するのですか?

個人的に好きな方法は、タプルに対して提供されている暗黙の順序付けを利用することです。

case class A(tag: String, load: Int) extends Ordered[A] {
  // Required as of Scala 2.11 for reasons unknown - the companion to Ordered
  // should already be in implicit scope
  import scala.math.Ordered.orderingToOrdered

  def compare(that: A): Int = (this.tag, this.load) compare (that.tag, that.load)
}

これは のコンパニオンが Ordered からの暗黙の変換を定義します。 Ordering[T] から Ordered[T] を実装しているすべてのクラスのスコープである Ordered . 暗黙の Ordering のための Tuple からの変換を可能にします。 TupleN[...] から Ordered[TupleN[...]] は、暗黙のうちに Ordering[TN] が存在する場合、すべての要素 T1, ..., TN を持たないデータ型に対してソートを行うことは意味がないため、常にそうでなければなりません。 Ordering .

タプルの暗黙の順序付けは、複合ソートキーを含むすべてのソートシナリオのためのものです。

as.sortBy(a => (a.tag, a.load))

この回答が好評だったので、私はそれを発展させ、以下のようなソリューションがある状況下ではエンタープライズグレード™と見なされる可能性があることを指摘したいと思います。

case class Employee(id: Int, firstName: String, lastName: String)

object Employee {
  // Note that because `Ordering[A]` is not contravariant, the declaration
  // must be type-parametrized in the event that you want the implicit
  // ordering to apply to subclasses of `Employee`.
  implicit def orderingByName[A <: Employee]: Ordering[A] =
    Ordering.by(e => (e.lastName, e.firstName))

  val orderingById: Ordering[Employee] = Ordering.by(e => e.id)
}

与えられた es: SeqLike[Employee] , es.sorted() は名前でソートされ es.sorted(Employee.orderingById) はidでソートします。これにはいくつかの利点があります。

  • ソートは、目に見えるコード成果物として一箇所で定義されます。これは、多くのフィールドで複雑なソートを行っている場合に便利です。
  • scala ライブラリで実装されているソート機能のほとんどは Ordering のインスタンスを使っているので、順序を直接提供することで、ほとんどの場合、暗黙の変換が不要になります。