我个人最喜欢的方法是使用提供的元组隐式排序,因为它是清晰,简洁和正确的:
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
S表示Tuple
S启用从一个转换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
,因此在大多数情况下,提供排序可以直接消除隐式转换。