我个人最喜欢的方法是使用提供的元组隐式排序,因为它清晰、简洁、正确:
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 的类。 Tuples 的隐式 Orderings 的存在可以实现从 TupleN[...] 到 Ordered[TupleN[...]] 的转换,前提是元组的所有元素 T1, ..., TN 都存在隐式 Ordering[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 的实例进行操作,因此在大多数情况下直接提供排序可以消除隐式转换。