1. 概述
排序是根据某种规则将数据集按升序或降序重新排列的过程。
它在日常开发中极为常见,比如我们在网站上查找最便宜的商品、通讯录中按姓名排序联系人等,都离不开排序。排序能显著提升搜索效率和用户体验。
之前我们介绍过 Java 中的排序,今天我们将聚焦在 Scala 中如何对集合进行排序。
2. 示例数据
在下面的例子中,我们将会对一组用户数据进行排序。每个用户包含 name
和 age
两个字段:
case class User(name: String, age: Int)
val users = List(
User("Mike", 43),
User("Mike", 16),
User("Kelly", 21)
)
3. 使用 sorted
方法
Scala 提供了一个专门用于排序的 sorted
方法,它会根据隐式提供的 Ordering
实例对集合中的元素进行排序:
def sorted[B >: A](implicit ord: Ordering[B]): Repr
其中:
A
是集合中元素的类型,在我们的例子中是User
Repr
是集合本身的实际类型,这里是List
如果我们直接调用:
users.sorted
编译器会报错 ❌,因为没有为 User
类型定义隐式的 Ordering
。
✅ 解决方法一:手动提供 Ordering
implicit val userOrdering: Ordering[User] = Ordering.by(_.age)
users.sorted shouldBe List(
User("Mike", 16),
User("Kelly", 21),
User("Mike", 43)
)
如果需要倒序排列,可以使用 .reverse
:
implicit val userOrdering: Ordering[User] = Ordering.by[User, Int](_.age).reverse
users.sorted shouldBe List(
User("Mike", 43),
User("Kelly", 21),
User("Mike", 16)
)
✅ 解决方法二:继承 Ordered
我们也可以让 User
继承 Ordered[User]
,实现 compare
方法:
case class User(name: String, age: Int) extends Ordered[User] {
override def compare(that: User): Int =
java.lang.Integer.compare(age, that.age)
}
users.sorted shouldBe List(
User("Mike", 16),
User("Kelly", 21),
User("Mike", 43)
)
这背后其实是 Scala 的一个隐式转换机制在起作用。编译器会自动将 Ordered[A]
转换为 Ordering[A]
,因为 Ordered
实际上继承了 Java 的 Comparable
接口:
trait Ordered[A] extends Any with java.lang.Comparable[A]
所以,只要类型实现了 Ordered
,就可以直接用于 sorted
。
4. 使用 sortBy
方法
如果我们要按某个字段排序,可以直接使用 sortBy
方法。它接受一个函数,返回要排序的字段,并要求该字段有对应的 Ordering
实例:
def sortBy[B](f: A => B)(implicit ord: Ordering[B]): Repr
例如,按 name
排序:
users.sortBy(_.name) shouldBe List(
User("Kelly", 21),
User("Mike", 43),
User("Mike", 16)
)
💡 你可能会问:我们有没有定义 Ordering[String]
?其实不需要,Scala 已经为常见的类型如 Int
、String
、Boolean
等预定义了 Ordering
。
✅ 多字段排序
Scala 还为元组(Tuple)预定义了 Ordering
,因此我们可以实现多字段排序:
users.sortBy(u => (u.name, u.age)) shouldBe List(
User("Kelly", 21),
User("Mike", 16),
User("Mike", 43)
)
5. 使用 sortWith
方法
如果你不想依赖 Ordering
,可以使用 sortWith
方法。它接受一个比较函数 (A, A) => Boolean
,返回 true
表示第一个元素排在前面:
def sortWith(lt: (A, A) => Boolean): Repr
例如,按年龄从大到小排序:
users.sortWith(_.age > _.age) shouldBe List(
User("Mike", 43),
User("Kelly", 21),
User("Mike", 16)
)
⚠️ 注意:sortWith
更加灵活,但也更容易出错,特别是在复杂的排序逻辑中,建议优先使用 sorted
和 sortBy
。
6. 小结
本文我们介绍了 Scala 中三种常用的排序方法:
方法 | 特点 |
---|---|
sorted |
依赖隐式 Ordering ,适合整体排序 |
sortBy |
根据字段排序,支持多字段 |
sortWith |
自定义比较函数,灵活但需谨慎使用 |
我们还了解了 Ordering
的作用机制,它是排序策略的核心抽象。
📚 完整代码可以在 GitHub 上找到:Baeldung/scala-tutorials