1. 概述
列表是开发中最常用的数据结构之一。在处理大量数据时,就地修改列表(Modify List In-Place)往往能显著提升性能,特别是在某些操作依赖前一个元素结果的场景下。
所谓“就地修改”,指的是在遍历列表的同时直接修改其内容,而不是创建新列表。本文将介绍几种 Kotlin 中实现列表就地修改的方式。
2. 可变与不可变列表
在 Kotlin 中,列表分为可变(MutableList
)和不可变(List
)两种类型:
✅ 可变列表允许添加、删除和修改元素
❌ 不可变列表一旦创建就不能更改内容
由于我们要实现的是就地修改,因此本文中将使用 MutableList
。
3. 使用 Iterator 就地修改
Kotlin 的 MutableList
提供了 listIterator()
方法,返回一个 MutableListIterator
。它除了支持 hasNext()
和 next()
,还提供了 set()
方法用于修改最后一次通过 next()
获取的元素。
示例:将列表中的偶数替换为 0:
fun replaceEvenNumbersBy0Iterator(list: MutableList<Int>): MutableList<Int> {
val iterator = list.listIterator()
while (iterator.hasNext()) {
val value = iterator.next()
if (value % 2 == 0) {
iterator.set(0)
}
}
return list
}
✅ 优点:语义清晰,适合在遍历中修改元素的场景
⚠️ 注意:set()
必须在调用 next()
后调用,否则会抛异常
4. 使用索引直接赋值修改
另一种方式是通过索引逐个访问并修改元素:
fun replaceEvenNumbersBy0Direct(list: MutableList<Int>): MutableList<Int> {
for (i in 0 until list.size) {
val value = list[i]
if (value % 2 == 0) {
list[i] = 0
}
}
return list
}
✅ 简洁直观,适合大多数线性修改场景
⚠️ 注意:频繁修改大列表时注意性能
5. 创建扩展方法实现通用修改
Kotlin 支持为已有类添加扩展方法,无需继承或装饰类。我们可以为 MutableList
添加一个 mapInPlace
方法,用于就地修改所有元素。
5.1 基本实现
fun <T> MutableList<T>.mapInPlace(mutator: (T) -> T) {
this.forEachIndexed { i, value ->
val changedValue = mutator(value)
this[i] = changedValue
}
}
使用示例:
val list = mutableListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
list.mapInPlace {
if (it % 2 == 0) 0 else it
}
// 输出:[1, 0, 3, 0, 5, 0, 7, 0, 9, 0]
println(list)
5.2 性能优化:仅当值变化时才更新
可以加入判断,避免不必要的赋值操作:
fun <T> MutableList<T>.mapInPlace(mutator: (T) -> T) {
this.forEachIndexed { i, value ->
val changedValue = mutator(value)
if (value != changedValue) {
this[i] = changedValue
}
}
}
5.3 扩展到 Array 类型
同样可以为数组添加类似功能:
fun <T> Array<T>.mapInPlace(mutator: (T) -> T) {
this.forEachIndexed { i, value ->
val changedValue = mutator(value)
if (value != changedValue) {
this[i] = changedValue
}
}
}
✅ 优点:复用性强,逻辑清晰
⚠️ 踩坑提醒:泛型中 ==
比较的是值,如果是对象类型要注意重写 equals()
6. 小结
本文介绍了几种 Kotlin 中实现列表就地修改的方法:
方法 | 适用场景 | 特点 |
---|---|---|
Iterator.set() |
遍历中修改元素 | 语义明确,适合迭代器风格 |
索引直接赋值 | 简单线性修改 | 简洁高效 |
扩展方法 | 通用、可复用 | 提升代码可读性与复用性 |
所有示例代码已上传至 GitHub,欢迎参考。