版本信息
scala 2.11.8
jdk 1.8
idea 2019
MacBook Pro
Ordering
在scala里要自定义一个类的话,一般都是case class,例如
case class Student(name:String, score:Int)
如果我们有了一个Student的数组
val students = Array(Student("bob", 80), Student("ann", 70), Student("carl", 99))
然后我们想对这个数组排序,指定下列排序规则之一
- 按score大小
- 按name字母序
- 按name的长度
排序的规则很灵活,根据需求可以自由定制
这个排序的任务在scala中,就可以通过Ordering实现
trait Ordering[T] extends Comparator[T] with PartialOrdering[T] with Serializable{}
比如,我们按照score排序
object AgeOrdering extends Ordering[Student] {
def compare(a: Student, b: Student) = a.score compare b.score
}
import scala.util.Sorting
Sorting.quickSort(students)(AgeOrdering)
Sorting
/** Sort array `a` with quicksort, using the Ordering on its elements.
* This algorithm sorts in place, so no additional memory is used aside from
* what might be required to box individual elements during comparison.
*/
def quickSort[K: Ordering](a: Array[K]): Unit = {
// Must have iN >= i0 or math will fail. Also, i0 >= 0.
def inner(a: Array[K], i0: Int, iN: Int, ord: Ordering[K]): Unit = {}
inner(a, 0, a.length, implicitly[Ordering[K]])
}
我们看到quickSort排序算法中inner函数有一个形式参数
ord: Ordering[K]
排序算法中比较两个Student, 借助了Ordering.compare方法
if (ord.compare(a(i0), a(iN - 1)) <= 0)
if (ord.compare(a(i0), a(iK)) < 0)
if (ord.compare(a(iN - 1), a(iK)) < 0) iN - 1 else iK
else i0
else
if (ord.compare(a(i0), a(iK)) < 0) i0
else
if (ord.compare(a(iN - 1), a(iK)) <= 0) iN - 1
else iK
所以我们在调用quickSort方法时,明确的传递了一个Ordering[Student]对象
object AgeOrdering extends Ordering[Student] {
def compare(a: Student, b: Student) = a.score compare b.score
}
import scala.util.Sorting
Sorting.quickSort(students)(AgeOrdering)
而且更为关键的一点是,我们看到AgeOrdering对象是
单
独
定
义
\color{#ea4335}{单独定义}
单独定义 的一个object,而不是一个class
我们并没有这么定义
case class Student(name:String, score:Int) extends Ordering[Student] {
def compare(a: Student, b: Student) = a.score compare b.score
}
如果这么定义的话,那么使用的时候就得这么写,可读性很差
import scala.util.Sorting
Sorting.quickSort(students)(Student("ordering",0))
把Ordering[Student]和Student分离开来,我个人认为有2点理由
- Student 的排序是多种多样的,没有固定唯一标准
- Sorting.quickSort方法只需要一个Ordering[Student]对象就够了
所以,我们在使用Ordering的时候,临时生成一个Ordering[T]对象即可满足我们的要求,
与T类定义完全解耦
Ordered
某些case class类有很多种排序方法,但是在特定的场景下
是有默认的大家都认可的排序规则的
比如对于Student,几乎所有人都认可的排序规则是学习成绩score
对于这些类的排序,我们就可以使用Ordered
trait Ordered[A] extends Any with java.lang.Comparable[A] {}
而且在类定义时,直接extends 或者 with Ordered[A],比如
case class Student(name: String, score: Int) extends Ordered[Student] {
def compare(that: Student): Int = this.score - that.score
}
不用显式传递Ordering参数, Ordered可隐式转换Ordering
import scala.util.Sorting
Sorting.quickSort(students)