scala – 容易习惯的方式来定义一个简单的case类的排序

我有一个简单的scala case类实例列表,我想使用list.sorted,以可预测的,词典顺序打印,但接收“没有隐式排序定义为…”。

是否存在一个隐式的,为案例类提供词典顺序?

有没有简单的惯用的方式混合字典词典排序到case类?

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

这是因为companion to Ordered定义了从Ordering [T]到Ordered [T]的隐式转换,这在任何实现Ordered的类的作用域中。如果对元组的所有元素T1,…,TN存在隐式排序[TN],则元组的隐式排序的存在使得能够从TupleN […]到Ordered [TupleN […]应该总是这样,因为对没有排序的数据类型排序没有意义。

Tuples的隐式排序是任何涉及复合排序键的排序方案的转换:

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实例操作,因此在大多数情况下提供排序直接消除了隐式转换。

http://stackoverflow.com/questions/19345030/easy-idiomatic-way-to-define-ordering-for-a-simple-case-class

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:scala – 容易习惯的方式来定义一个简单的case类的排序