Kotlin列表操作指南
Kotlin 列表基础
Kotlin 中的列表是一种有序集合,它允许我们存储多个元素,并且可以根据元素的索引来访问和操作这些元素。列表分为可变列表(MutableList
)和不可变列表(List
)。
不可变列表
不可变列表一旦创建,其内容就不能被修改。我们可以使用 listOf
函数来创建不可变列表。例如:
val numbers = listOf(1, 2, 3, 4, 5)
println(numbers)
上述代码创建了一个包含整数 1 到 5 的不可变列表,并将其打印出来。
不可变列表的优点在于线程安全,适合在多个线程访问的场景下使用。它保证了数据的一致性,不会因为其他线程的修改而导致数据状态的混乱。
可变列表
可变列表允许我们在创建后添加、删除和修改元素。使用 mutableListOf
函数来创建可变列表。例如:
val mutableNumbers = mutableListOf(1, 2, 3)
mutableNumbers.add(4)
mutableNumbers[2] = 33
println(mutableNumbers)
这里我们创建了一个可变列表 mutableNumbers
,初始包含 1、2、3。然后添加了元素 4,并将索引为 2 的元素修改为 33,最后打印列表。
可变列表适用于需要频繁修改数据的场景,比如在程序运行过程中动态添加或删除元素的情况。但在多线程环境下需要注意同步问题,否则可能会出现数据竞争。
访问列表元素
通过索引访问
在 Kotlin 中,我们可以像在其他编程语言中一样,通过索引来访问列表中的元素。索引从 0 开始。例如:
val fruits = listOf("apple", "banana", "cherry")
println(fruits[1])
上述代码会打印出 banana
,因为索引 1 对应列表中的第二个元素。
在使用索引访问时需要注意边界检查。如果访问的索引超出了列表的范围,会抛出 IndexOutOfBoundsException
。例如:
val fruits = listOf("apple", "banana", "cherry")
try {
println(fruits[3])
} catch (e: IndexOutOfBoundsException) {
println("Index out of bounds: $e")
}
这段代码尝试访问索引 3,由于列表只有 3 个元素,索引范围是 0 到 2,所以会捕获到 IndexOutOfBoundsException
并打印错误信息。
使用 get
方法
除了使用方括号语法,还可以使用 get
方法来访问列表元素。例如:
val numbers = listOf(10, 20, 30)
println(numbers.get(2))
get
方法在功能上与方括号语法相同,但在某些情况下,比如在链式调用中,使用 get
方法可能会使代码更易读。
遍历列表
for
循环遍历
使用传统的 for
循环来遍历列表是一种常见的方式。例如:
val animals = listOf("dog", "cat", "bird")
for (animal in animals) {
println(animal)
}
在这个例子中,for
循环依次将 animals
列表中的每个元素赋值给 animal
变量,并打印出来。
如果需要获取元素的索引,可以使用 withIndex
扩展函数。例如:
val fruits = listOf("apple", "banana", "cherry")
for ((index, fruit) in fruits.withIndex()) {
println("Index $index: $fruit")
}
withIndex
函数会返回一个包含索引和元素的 Pair
,通过解构赋值,我们可以在循环中同时获取索引和元素。
forEach
遍历
forEach
是 Kotlin 提供的一种更简洁的遍历方式,它接受一个函数作为参数,对列表中的每个元素执行该函数。例如:
val numbers = listOf(1, 2, 3, 4)
numbers.forEach { number ->
println(number * 2)
}
这里 forEach
对 numbers
列表中的每个元素乘以 2 并打印。如果函数体只有一行代码,可以省略花括号,使代码更加简洁:
val numbers = listOf(1, 2, 3, 4)
numbers.forEach { println(it * 2) }
这里 it
是 forEach
函数闭包中的默认参数名,表示当前遍历到的元素。
forEachIndexed
遍历
forEachIndexed
类似于 forEach
,但它会同时提供元素的索引。例如:
val colors = listOf("red", "green", "blue")
colors.forEachIndexed { index, color ->
println("Index $index: $color")
}
在这个例子中,forEachIndexed
函数的闭包接受索引 index
和元素 color
,并打印出每个元素及其索引。
列表操作 - 添加元素
可变列表添加元素
对于可变列表,我们可以使用 add
方法来添加单个元素。add
方法有两种形式,一种是将元素添加到列表末尾,另一种是在指定索引位置插入元素。
添加到末尾:
val mutableList = mutableListOf(1, 2, 3)
mutableList.add(4)
println(mutableList)
上述代码将元素 4 添加到 mutableList
的末尾。
在指定位置插入:
val mutableList = mutableListOf(1, 2, 3)
mutableList.add(1, 10)
println(mutableList)
这里将元素 10 插入到索引 1 的位置,原索引 1 及之后的元素会向后移动。
不可变列表添加元素
不可变列表本身不能被修改,但我们可以通过创建新列表的方式来实现类似添加元素的效果。例如,使用 plus
函数:
val list = listOf(1, 2, 3)
val newList = list.plus(4)
println(newList)
plus
函数会创建一个新的列表,包含原列表的所有元素以及新添加的元素 4。注意,原列表 list
并没有被修改。
我们还可以使用 +
运算符来达到相同的效果:
val list = listOf(1, 2, 3)
val newList = list + 4
println(newList)
列表操作 - 删除元素
可变列表删除元素
在可变列表中,可以使用 remove
方法删除指定元素。例如:
val mutableList = mutableListOf(1, 2, 3, 2)
mutableList.remove(2)
println(mutableList)
上述代码会删除列表中第一次出现的元素 2。如果列表中有多个相同元素,只会删除第一个。
要删除指定索引位置的元素,可以使用 removeAt
方法:
val mutableList = mutableListOf(1, 2, 3)
mutableList.removeAt(1)
println(mutableList)
这里删除了索引为 1 的元素 2。
不可变列表删除元素
不可变列表同样不能直接修改,但可以通过创建新列表来达到删除元素的目的。例如,使用 filter
函数:
val list = listOf(1, 2, 3, 4)
val newList = list.filter { it != 3 }
println(newList)
filter
函数会创建一个新列表,其中包含原列表中满足指定条件的元素。这里的条件是元素不等于 3,所以新列表不包含元素 3。
列表操作 - 修改元素
可变列表修改元素
对于可变列表,可以直接通过索引来修改元素的值。例如:
val mutableList = mutableListOf(1, 2, 3)
mutableList[1] = 22
println(mutableList)
上述代码将索引为 1 的元素从 2 修改为 22。
还可以使用 set
方法来达到相同的效果:
val mutableList = mutableListOf(1, 2, 3)
mutableList.set(1, 22)
println(mutableList)
set
方法接受索引和新值作为参数,将指定索引位置的元素替换为新值。
不可变列表修改元素
不可变列表不能直接修改元素,但可以通过创建新列表来模拟修改操作。例如,先使用 filter
函数过滤掉要修改的元素,再使用 plus
函数添加修改后的元素:
val list = listOf(1, 2, 3)
val newList = list.filter { it != 2 } + 22
println(newList)
这里先过滤掉元素 2,然后添加修改后的元素 22,从而创建了一个新列表。
列表转换
转换为数组
在 Kotlin 中,可以将列表转换为数组。对于不可变列表,可以使用 toArray
函数:
val list = listOf(1, 2, 3)
val array = list.toArray()
println(array.contentToString())
toArray
函数会返回一个包含列表元素的数组。注意,这里返回的是 Array<Any>
类型的数组,如果列表元素类型是确定的,可以使用带类型参数的 toTypedArray
函数。例如:
val list = listOf(1, 2, 3)
val intArray = list.toTypedArray()
println(intArray.contentToString())
对于可变列表,同样可以使用 toArray
和 toTypedArray
函数进行转换。
转换为其他集合类型
Kotlin 列表还可以转换为其他集合类型,比如 Set
。可以使用 toSet
函数将列表转换为集合。例如:
val list = listOf(1, 2, 2, 3)
val set = list.toSet()
println(set)
这里将列表转换为集合后,集合中会去除重复元素,所以 set
为 [1, 2, 3]
。
也可以将列表转换为 Map
。假设列表中的元素是 Pair
类型,可以使用 toMap
函数将其转换为 Map
。例如:
val list = listOf(Pair("a", 1), Pair("b", 2))
val map = list.toMap()
println(map)
列表过滤与筛选
使用 filter
函数
filter
函数用于从列表中筛选出满足指定条件的元素,返回一个新的列表。例如,筛选出列表中的偶数:
val numbers = listOf(1, 2, 3, 4, 5, 6)
val evenNumbers = numbers.filter { it % 2 == 0 }
println(evenNumbers)
这里的 filter
函数接受一个 lambda 表达式作为参数,该表达式定义了筛选条件,即元素对 2 取余等于 0 为偶数。
使用 filterNot
函数
filterNot
函数与 filter
函数相反,它返回列表中不满足指定条件的元素组成的新列表。例如,筛选出列表中的奇数:
val numbers = listOf(1, 2, 3, 4, 5, 6)
val oddNumbers = numbers.filterNot { it % 2 == 0 }
println(oddNumbers)
使用 filterNotNull
函数
当列表中可能包含 null
值时,可以使用 filterNotNull
函数来过滤掉 null
值,返回一个不包含 null
的新列表。例如:
val nullableList = listOf(1, null, 3, null, 5)
val nonNullList = nullableList.filterNotNull()
println(nonNullList)
这里 filterNotNull
函数会去除 nullableList
中的 null
值,返回 [1, 3, 5]
。
列表映射与转换
使用 map
函数
map
函数用于将列表中的每个元素按照指定的规则进行转换,返回一个新的列表。例如,将列表中的每个数字乘以 2:
val numbers = listOf(1, 2, 3)
val doubledNumbers = numbers.map { it * 2 }
println(doubledNumbers)
这里 map
函数对 numbers
列表中的每个元素应用 it * 2
的转换规则,返回一个新列表 [2, 4, 6]
。
使用 flatMap
函数
flatMap
函数先对列表中的每个元素应用一个转换函数,该函数返回一个列表,然后将所有这些返回的列表合并成一个新列表。例如,有一个包含多个列表的列表,将其扁平化:
val nestedList = listOf(listOf(1, 2), listOf(3, 4))
val flatList = nestedList.flatMap { it }
println(flatList)
这里 flatMap
函数将 nestedList
中的每个子列表进行合并,返回 [1, 2, 3, 4]
。
使用 mapNotNull
函数
mapNotNull
函数与 map
函数类似,但它会过滤掉转换过程中产生的 null
值。例如,将列表中的字符串转换为整数,但有些字符串可能无法转换为有效的整数,使用 mapNotNull
可以过滤掉这些无效转换:
val stringList = listOf("1", "two", "3")
val intList = stringList.mapNotNull { it.toIntOrNull() }
println(intList)
这里 toIntOrNull
函数尝试将字符串转换为整数,如果转换失败返回 null
,mapNotNull
函数会过滤掉这些 null
值,返回 [1, 3]
。
列表聚合操作
使用 reduce
函数
reduce
函数用于对列表中的元素进行聚合操作,它接受一个二元操作函数,将列表中的元素两两结合,最终返回一个单一的结果。例如,计算列表中所有元素的和:
val numbers = listOf(1, 2, 3, 4)
val sum = numbers.reduce { acc, number -> acc + number }
println(sum)
这里 reduce
函数从列表的第一个元素开始,将 acc
(初始为第一个元素)与后续元素依次通过 acc + number
的操作进行聚合,最终返回所有元素的和 10。
使用 fold
函数
fold
函数与 reduce
函数类似,但它可以指定一个初始值。例如,计算列表中所有元素的乘积,从 1 开始:
val numbers = listOf(2, 3, 4)
val product = numbers.fold(1) { acc, number -> acc * number }
println(product)
这里 fold
函数从初始值 1 开始,与列表中的元素依次通过 acc * number
的操作进行聚合,返回乘积 24。
使用 sum
、product
等函数
Kotlin 为数字类型的列表提供了一些便捷的聚合函数,如 sum
用于计算列表元素的和,product
用于计算列表元素的乘积。例如:
val numbers = listOf(1, 2, 3, 4)
val sum = numbers.sum()
val product = numbers.product()
println("Sum: $sum, Product: $product")
这些函数简化了常见的聚合操作,不需要手动编写 reduce
或 fold
逻辑。
列表排序
自然排序
对于实现了 Comparable
接口的元素类型的列表,可以使用 sorted
函数进行自然排序。例如,对整数列表进行升序排序:
val numbers = listOf(3, 1, 4, 2)
val sortedNumbers = numbers.sorted()
println(sortedNumbers)
这里 sorted
函数会返回一个新的已排序的列表 [1, 2, 3, 4]
,原列表 numbers
保持不变。
自定义排序
如果需要自定义排序规则,可以使用 sortedWith
函数,并传入一个比较器。例如,对字符串列表按照长度进行排序:
val strings = listOf("apple", "banana", "cherry", "date")
val sortedByLength = strings.sortedWith(compareBy { it.length })
println(sortedByLength)
这里 compareBy
函数创建了一个比较器,按照字符串长度进行比较,sortedWith
函数使用这个比较器对列表进行排序,返回按长度排序后的列表。
对于可变列表,可以使用 sort
和 sortWith
函数直接对列表进行排序,而不是返回一个新列表。例如:
val mutableList = mutableListOf(3, 1, 4, 2)
mutableList.sort()
println(mutableList)
这里 sort
函数直接对 mutableList
进行升序排序。
列表查找与搜索
使用 find
函数
find
函数用于在列表中查找满足指定条件的第一个元素。如果找到则返回该元素,否则返回 null
。例如,在列表中查找第一个偶数:
val numbers = listOf(1, 3, 4, 5)
val firstEven = numbers.find { it % 2 == 0 }
println(firstEven)
这里 find
函数返回 4,因为 4 是列表中第一个满足偶数条件的元素。
使用 indexOf
和 lastIndexOf
函数
indexOf
函数用于查找指定元素在列表中的第一次出现的索引位置,如果不存在则返回 -1。例如:
val fruits = listOf("apple", "banana", "cherry", "banana")
val index = fruits.indexOf("banana")
println(index)
这里 indexOf
函数返回 1,因为 "banana" 第一次出现在索引 1 的位置。
lastIndexOf
函数与 indexOf
函数类似,但它查找的是指定元素最后一次出现的索引位置。例如:
val fruits = listOf("apple", "banana", "cherry", "banana")
val lastIndex = fruits.lastIndexOf("banana")
println(lastIndex)
这里 lastIndexOf
函数返回 3,因为 "banana" 最后一次出现在索引 3 的位置。
列表分组
使用 groupBy
函数可以根据指定的分组依据将列表中的元素分组。例如,将整数列表按照奇偶性分组:
val numbers = listOf(1, 2, 3, 4, 5)
val groupedNumbers = numbers.groupBy { if (it % 2 == 0) "even" else "odd" }
println(groupedNumbers)
这里 groupBy
函数根据元素是偶数还是奇数进行分组,返回一个 Map
,其中键是分组的标识("even" 或 "odd"),值是属于该组的元素列表。
列表的高级操作 - 滑动窗口
使用 windowed
函数可以在列表上创建滑动窗口。例如,对列表中的元素进行相邻两个元素的求和:
val numbers = listOf(1, 2, 3, 4)
val windowedSums = numbers.windowed(2).map { it.sum() }
println(windowedSums)
这里 windowed(2)
创建了大小为 2 的滑动窗口,然后对每个窗口内的元素求和,最终返回 [3, 5, 7]
。
列表的高级操作 - 拉链操作
使用 zip
函数可以将两个列表按元素位置进行配对。例如,将两个列表中的元素一一对应相乘:
val list1 = listOf(1, 2, 3)
val list2 = listOf(4, 5, 6)
val multiplied = list1.zip(list2).map { (a, b) -> a * b }
println(multiplied)
这里 zip
函数将 list1
和 list2
按位置配对,然后 map
函数对每对元素进行相乘操作,返回 [4, 10, 18]
。
通过以上对 Kotlin 列表操作的详细介绍,开发者可以更加灵活高效地处理列表数据,根据不同的业务需求选择合适的操作方法,提高代码的质量和性能。无论是简单的元素访问、遍历,还是复杂的聚合、分组等操作,Kotlin 都提供了丰富且易用的函数和方法来满足需求。