1. 概述

排序是根据某种规则将数据集按升序或降序重新排列的过程。

它在日常开发中极为常见,比如我们在网站上查找最便宜的商品、通讯录中按姓名排序联系人等,都离不开排序。排序能显著提升搜索效率和用户体验。

之前我们介绍过 Java 中的排序,今天我们将聚焦在 Scala 中如何对集合进行排序。

2. 示例数据

在下面的例子中,我们将会对一组用户数据进行排序。每个用户包含 nameage 两个字段:

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 已经为常见的类型如 IntStringBoolean 等预定义了 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 更加灵活,但也更容易出错,特别是在复杂的排序逻辑中,建议优先使用 sortedsortBy

6. 小结

本文我们介绍了 Scala 中三种常用的排序方法:

方法 特点
sorted 依赖隐式 Ordering,适合整体排序
sortBy 根据字段排序,支持多字段
sortWith 自定义比较函数,灵活但需谨慎使用

我们还了解了 Ordering 的作用机制,它是排序策略的核心抽象。

📚 完整代码可以在 GitHub 上找到:Baeldung/scala-tutorials


原始标题:A Guide to Sorting in Scala

« 上一篇: Scala 元组指南