为简单的案例类定义排序的简单惯用方法 [英] Easy idiomatic way to define Ordering for a simple case class

查看:21
本文介绍了为简单的案例类定义排序的简单惯用方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的 Scala 案例类实例列表,我想使用 list.sorted 以可预测的字典顺序打印它们,但收到没有为...定义隐式排序".

I have a list of simple scala case class instances and I want to print them in predictable, lexicographical order using list.sorted, but receive "No implicit Ordering defined for ...".

是否存在为案例类提供字典顺序的隐式?

Is there exist an implicit that provides lexicographical ordering for case classes?

是否有简单的惯用方法将字典顺序混合到 case 类中?

Is there simple idiomatic way to mix-in lexicographical ordering into case class?

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)

推荐答案

我个人最喜欢的方法是利用元组提供的隐式排序,因为它清晰、简洁且正确:

My personal favorite method is to make use of the provided implicit ordering for Tuples, as it is clear, concise, and correct:

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.Tuple 的隐式 Ordering 的存在使得从 TupleN[...] 转换为 Ordered[TupleN[...]] 为元组的所有元素 T1, ..., TN 提供了一个隐式的 Ordering[TN] ,这应该总是如此,因为对没有 Ordering 的数据类型进行排序是没有意义的.

This works because the companion to Ordered defines an implicit conversion from Ordering[T] to Ordered[T] which is in scope for any class implementing Ordered. The existence of implicit Orderings for Tuples enables a conversion from TupleN[...] to Ordered[TupleN[...]] provided an implicit Ordering[TN] exists for all elements T1, ..., TN of the tuple, which should always be the case because it makes no sense to sort on a data type with no Ordering.

元组的隐式排序是任何涉及复合排序键的排序场景的首选:

The implicit ordering for Tuples is your go-to for any sorting scenario involving a composite sort key:

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

由于这个答案已被证明很受欢迎,我想对其进行扩展,并指出类似于以下内容的解决方案在某些情况下可能被视为企业级™:

As this answer has proven popular I would like to expand on it, noting that a solution resembling the following could under some circumstances be considered enterprise-grade™:

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 排序.这有几个好处:

Given es: SeqLike[Employee], es.sorted() will sort by name, and es.sorted(Employee.orderingById) will sort by id. This has a few benefits:

  • 排序在单个位置定义为可见的代码工件.如果您对许多字段进行复杂排序,这将非常有用.
  • scala 库中实现的大多数排序功能都使用 Ordering 的实例运行,因此在大多数情况下直接提供排序可以消除隐式转换.
  • The sorts are defined in a single location as visible code artifacts. This is useful if you have complex sorts on many fields.
  • Most sorting functionality implemented in the scala library operates using instances of Ordering, so providing an ordering directly eliminates an implicit conversion in most cases.

这篇关于为简单的案例类定义排序的简单惯用方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆