进阶集合操作
源:Kotlin standard library - Collections
Kotlin 集合库不仅仅是 Java java.util 的包装,它通过内联函数提供了极其强大的声明式操作。掌握这些进阶操作可以显著减少模板代码,并提高代码的可读性和执行效率。
集合构建器 (Collection Builders) Kotlin 1.6+
如果你需要创建一个复杂的只读集合,通常的做法是先创建一个 MutableList,填充数据后再调用 toList()。使用 buildList 可以更优雅地完成这一切。
kotlin
val activeUsers = buildList {
add("Alice")
if (includeAdmin) add("Admin")
addAll(otherUsers.filter { it.isActive })
// 块结束时自动转换为不可变的 List
}kotlin
val permissions = buildMap<String, Int> {
put("read", 1)
put("write", 2)
if (isSuperUser) put("delete", 4)
}分组与聚合 (Grouping)
groupingBy:高性能聚合
groupBy 会直接生成一个 Map<K, List<V>>,如果你只是为了对每个分组进行计数或求和,groupBy 会产生不必要的中间 List 对象。groupingBy 配合 eachCount 或 fold 则更加高效。
kotlin
val words = "one two one three two one".split(" ")
// ❌ 效率较低:创建了多个中间 List
val counts1 = words.groupBy { it }.mapValues { it.value.size }
// ✅ 推荐做法:不创建中间 List
val counts2 = words.groupingBy { it }.eachCount()kotlin
val orders = listOf(Order("A", 10), Order("B", 20), Order("A", 5))
// 按类别累加金额
val totals = orders.groupingBy { it.category }
.fold(0) { accumulator, order ->
accumulator + order.amount
}窗口与分块 (Windowing & Chunking)
在处理连续数据(如折线图平滑、滑动平均值)时,这两个函数非常有用。
chunked:分批处理
kotlin
val numbers = (1..10).toList()
// 每 3 个一组
val chunks = numbers.chunked(3)
// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
// 带转换操作
numbers.chunked(3) { it.sum() } // [6, 15, 24, 10]windowed:滑动窗口
kotlin
val sequence = listOf(1, 2, 3, 4, 5)
// 窗口大小 3,步长 1
val windows = sequence.windowed(3)
// [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
// 窗口大小 3,步长 3 (等同于 chunked)
val windows2 = sequence.windowed(3, step = 3, partialWindows = true)关联与分区 (Associating & Partition)
associate 系列:构建 Map 的利器
kotlin
// Key 转换:使用对象属性作为 Key
val userMap = users.associateBy { it.id }
// Map<Id, User>kotlin
// Value 转换:保持原对象为 Key,计算新值为 Value
val userRoles = users.associateWith { getRole(it) }
// Map<User, Role>kotlin
// 自定义 Key-Value 对
val nameToLength = users.associate { it.name to it.name.length }partition:一分为二
当你需要根据条件将集合拆分为“符合条件”和“不符合条件”的两部分时,partition 比两次 filter 更高效且逻辑更清晰。
kotlin
val (adults, minors) = users.partition { it.age >= 18 }
println("成年人: $adults")
println("未成年: $minors")集合操作符对比表
| 操作符 | 结果类型 | 说明 |
|---|---|---|
zip | List<Pair<T, R>> | 将两个集合按索引配对成 Pair |
zipWithNext | List<Pair<T, T>> | 将集合中相邻的元素两两配对 |
flatMap | List<R> | 转换每个元素为集合,并将所有结果展平 |
flatten | List<T> | 将 List<List<T>> 展平为 List<T> |
scan | List<R> | 类似 fold,但会保留每一个中间计算结果 |
性能准则
- 优先使用 Sequence:如果链式操作超过 3 个,且集合数据量较大,请务必使用
.asSequence()开启惰性计算。 - 避免反复创建 Mutable 集合:在循环中使用
+=操作List会导致频繁的数组拷贝。应优先使用buildList或toMutableList()后再一次性转换。 - 注意 Iterable vs Sequence:
Iterable:每一步都会创建一个新的中间集合。Sequence:只有在遇到终结操作(如toList(),first())时才会执行计算。