1. 概述
在 Kotlin 中操作集合是开发中非常常见的任务。作为集合中最基础的类型之一,列表(List) 经常需要我们在遍历的同时动态添加新元素。
本文将介绍几种在 Kotlin 中遍历列表时添加元素的常见方式,并结合示例代码讲解不同场景下的实现方案。
2. 问题引入
为了更直观地理解问题,我们来看一个例子:
假设我们有如下字符串列表:
["ab", "a", "cd", "c", "xyz"]
现在我们希望 **在遍历过程中,每当遇到长度大于 1 的字符串时,就在其后插入一个标记字符串 <- a long one
**,最终结果如下:
["ab", "<- a long one", "a", "cd", "<- a long one", "c", "xyz", "<- a long one"]
或者,**根据需求不同,我们可能需要在这些“长字符串”前插入 a long one ->
**:
["a long one ->", "ab", "a", "a long one ->", "cd", "c", "a long one ->", "xyz"]
Kotlin 中有只读列表和可变列表之分,因此我们需根据列表类型和插入位置的不同分别处理。
3. 当列表是只读的(Read-only)
如果列表是只读的:
val myList = listOf("ab", "a", "cd", "c", "xyz")
那么我们无法直接修改该列表。此时,我们通常的做法是创建一个可变列表,遍历原列表并按需添加元素,最后返回一个新列表。
3.1 使用 forEach()
我们可以使用 forEach()
遍历原列表,并将符合条件的元素插入到一个新的 mutableListOf()
中:
fun byForEach(list: List<String>): List<String> {
val result = mutableListOf<String>()
list.forEach {
result += it
if (it.length > 1) {
result += "<- a long one"
}
}
return result.toList()
}
✅ 优点:逻辑清晰,适合初学者理解。
❌ 缺点:需要手动创建中间列表,代码略显冗长。
测试:
assertEquals(
listOf("ab", "<- a long one", "a", "cd", "<- a long one", "c", "xyz", "<- a long one"),
byForEach(myList)
)
3.2 使用 buildList()
Kotlin 提供了 buildList()
函数,可以更简洁地构建列表:
fun byBuildList(list: List<String>) =
buildList {
list.forEach {
this += it
if (it.length > 1) {
this += "<- a long one"
}
}
}
✅ 优点:语法简洁,使用 +=
操作符即可添加元素。
✅ 内部使用可变列表,最终返回只读列表。
测试:
assertEquals(
listOf("ab", "<- a long one", "a", "cd", "<- a long one", "c", "xyz", "<- a long one"),
byBuildList(myList)
)
3.3 在元素前插入内容
如果我们希望在“长字符串”前面插入内容,只需调整插入顺序即可。
以 buildList()
为例:
fun addBeforeByBuildList(list: List<String>) =
buildList {
list.forEach {
if (it.length > 1) {
this += "a long one ->"
}
this += it
}
}
测试:
assertEquals(
listOf("a long one ->", "ab", "a", "a long one ->", "cd", "c", "a long one ->", "xyz"),
addBeforeByBuildList(myList)
)
4. 当列表是可变的(Mutable)
如果列表是可变的:
val myMutableList = mutableListOf("ab", "a", "cd", "c", "xyz")
我们无需创建新列表,可以直接在遍历过程中修改原列表。
4.1 使用 ListIterator
使用 ListIterator
可以在遍历的同时修改列表内容,比如插入或删除元素:
fun byListIterator(list: MutableList<String>) {
val it = list.listIterator()
for (e in it) {
if (e.length > 1) {
it.add("<- a long one")
}
}
}
✅ 优点:无需额外内存,直接修改原列表。
⚠️ 注意:不能使用普通 for
循环或 forEach
直接修改列表,否则会抛出 ConcurrentModificationException
。
测试:
byListIterator(myMutableList)
assertEquals(
listOf("ab", "<- a long one", "a", "cd", "<- a long one", "c", "xyz", "<- a long one"),
myMutableList
)
4.2 在元素前插入内容
如果我们希望在“长字符串”前面插入内容,可以使用 ListIterator.previous()
和 next()
配合完成:
fun addBeforeByListIterator(list: MutableList<String>) {
val it = list.listIterator()
for (e in it) {
if (e.length > 1) {
it.previous()
it.add("a long one ->")
it.next()
}
}
}
✅ 通过 previous()
回退指针,插入新元素,再通过 next()
恢复遍历位置。
测试:
val myMutableList = mutableListOf("ab", "a", "cd", "c", "xyz")
addBeforeByListIterator(myMutableList)
assertEquals(
listOf("a long one ->", "ab", "a", "a long one ->", "cd", "c", "a long one ->", "xyz"),
myMutableList
)
5. 总结
在 Kotlin 中,我们可以通过多种方式在遍历列表时动态添加元素:
场景 | 方法 | 特点 |
---|---|---|
只读列表 | forEach() + mutableListOf() |
简单易懂,适合新手 |
只读列表 | buildList() |
语法简洁,推荐使用 |
可变列表 | ListIterator |
原地修改,节省内存 |
插入位置 | 调整插入顺序 | 前插需配合 previous() 和 next() |
⚠️ 注意:在使用可变列表时,不能直接使用普通循环修改原列表,否则会触发并发修改异常。
完整示例代码可参考 GitHub 项目地址。