# Kotlin教程 - 7 容器
什么是容器?
容器就是可以存储多个数据的一种数据类型,容器内的每一个数据称之为元素,其中的元素可以是任意类型的数据,包括字符串、数字、布尔,甚至是容器等等。
例如有一个班级,有40个学生,我们肯定不能定义40个变量来存储学生的信息,有1000个人,那不要命了,我们可以将所有学生的信息放到容器中。
在 Kotlin 中常用的容器分为4类:
- 数组(Array)
- 列表(List)
- 集合(Set)
- 字典(Map)
不同的容器有不同的特点,例如:
- 是否支持重复的元素,有的容器中的元素不能重复,有的可以。
- 是否有序
下面一一介绍。
# 7.1 数组
数组是一种有序的容器,用于存储相同类型的元素。
数组的主要特点:
- 有序
- 只能存储相同类型的元素
- 大小在创建的时候就确定了,大小不可变
# 1 创建数组
方式1:arrayOf
fun main() {
    // 创建一个用于存储整数的数组,并存储了1、2、3、4、5
    val numberArray1: Array<Int> = arrayOf(1, 2, 3, 4, 5)
    // 类型也可以省略
    val numberArray2 = arrayOf(1, 2, 3, 4, 5)
}
2
3
4
5
6
方式2:创建空组数
fun main() {
    // 创建一个空数组,长度为5,后面可以修改数组中的值
    val emptyArray = arrayOfNulls<String>(5)
}
2
3
4
方式3:数组构造函数
fun main() {
    // 创建一个整形数组,长度为5,其中的元素都是0
    val numberArray = Array(5) { 0 }
    // 创建一个字符串类型数组,长度为5,其中的元素都是空字符串
    val stringArray = Array(5) { "" }
    // 创建一个可空的字符串数组,长度为5,其中的元素都是null
    val nullableArray = Array<String?>(5) { null }
    // 创建一个整数数组,长度为5,并将元素初始化为索引的两倍,则其中的元素为[0, 2, 4, 6, 8]
    val numberArray2 = Array(5) { index -> index * 2 }
    // 创建一个字符串数组,长度为5,其中的元素使用when表达式通过index进行设置,最后的结果["Hello","old","are","you","!"]
    val stringArray2 = Array(5) { index ->
        when (index) {
            0 -> "Hello"
            1 -> "old"
            2 -> "are"
            3 -> "you"
            4 -> "!"
            else -> throw IndexOutOfBoundsException("数组索引越界")   // 异常后面再讲
        }
    }
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
使用数组构造函数创建,还可以使用 lambda 表达式,根据 index 来设置元素。
方式4:使用原生整数数组类型
以下以 IntArray 为例, IntArray 是一个整形数组,与泛型数组 Array<Int> 不同,IntArray 是一个特定于整数的数组类型。
举个栗子:
fun main() {
    // 使用IntArray构造函数初始化,长度为5,初始值为 0 的数组
    val numbers1 = IntArray(5) 
    // 使用 intArrayOf 函数 创建一个包含指定元素的数组
    val numbers2 = intArrayOf(1, 2, 3, 4, 5)
}
2
3
4
5
6
7
Kotlin 中除了 IntArray,还有一些其他的原生数组类型,以及泛型数组类型。以下是一些常见的数组类型:
- IntArray:用于存储整数。
- DoubleArray:用于存储双精度浮点数。
- FloatArray:用于存储单精度浮点数。
- LongArray:用于存储长整数。
- ShortArray:用于存储短整数。
- ByteArray:用于存储字节。
- CharArray:用于存储字符。
- BooleanArray:用于存储布尔值。
这些原生数组类型直接使用底层的原生数据类型,因此具有高效的性能。
# 2 基础操作
# 获取长度
使用 size() 方法可以获取到数组的长度。
fun main() {
    val numbers: Array<Int> = arrayOf(1, 2, 3, 4, 5)
    println("数组长度:" + numbers.size)    // 输出:5
}
2
3
4
# 访问元素
可以使用下标来访问列表中的元素或修改数组中的元素,从0开始,注意不要越界,下标越界会报错。
fun main() {
    val numbers: Array<Int> = arrayOf(1, 2, 3, 4, 5)
    var num = numbers[0]      // 获取第一个元素
    println(num)      				// 输出:1
    num = numbers[numbers.lastIndex]     // 获取最后一个元素
    println(num)      				// 输出:5
    numbers[0] = 100        	// 修改元素
    println(numbers[0])
}
2
3
4
5
6
7
8
9
10
11
因为数组的长度创建后就无法更改了,所以我们无法删除和添加更多到元素到数组中,只能修改数组中的元素。
除了使用 [index] 的方式访问元素,还可以使用 get 函数来访问。
举个栗子:
fun main() {
    val numbers: Array<Int> = arrayOf(1, 2, 3, 4, 5)
    val num1 = numbers.get(0)       				// 获取第一个元素
    val num6 = numbers.getOrElse(6) { 0 }   // 获取index为6的元素
    val num7 = numbers.getOrNull(7) ?: 0    // 获取index为7的元素
}
2
3
4
5
6
- 可以使用 get(index)函数获取指定index的元素,如果index大于数组长度,或报错;
- 可以使用 getOrElse(Index)获取指定index的元素,如果越界,则返回lambda表达式的结果;
- 可以使用 getOrNull(Index)获取指定index的元素,如果越界,则返回null,在上面的代码中,我们结合?:操作符,如果为null,就赋 0 。
Kotlin 还提供了一些获取指定位置元素的函数。
举个栗子:
fun main() {
    val numbers: Array<Int> = arrayOf(1, 2, 3, 4, 5)
    val firstElement = numbers.first()  // 获取第一个额原始
    val lastElement = numbers.last()    // 获取最后一个元素
}
2
3
4
5
# 3 遍历数组
使用 for-in 循环
可以使用 for-in 循环来遍历数组的元素。这适用于所有类型的数组,包括原生数组和泛型数组。
fun main() {
    val colors = arrayOf("Red", "Blue", "Green")
    for (color in colors) {   // 依次取出数组中的每个元素
        println(color)
    }
}
2
3
4
5
6
7
使用索引和 indices 属性
如果需要访问数组的索引以及元素,可以使用数组的 indices 属性,然后通过索引来访问元素。
fun main() {
    val colors = arrayOf("Red", "Blue", "Green")
    for (index in colors.indices) {     // index 每个元素的索引
        println("Index: $index, Element: ${colors[index]}")     // 通过索引取出每个元素
    }
}
2
3
4
5
6
7
使用 forEach 函数
Kotlin 提供了 forEach 函数,可用于遍历数组元素。这对于处理集合更加方便。
fun main() {
    val colors = arrayOf("Red", "Blue", "Green")
    colors.forEach { element ->
        println(element)           // 依次取出数组中的元素
    }
}
2
3
4
5
6
7
使用 forEachIndexed 函数
如果需要同时访问索引和元素,可以使用 forEachIndexed 函数。
fun main() {
    val colors = arrayOf("Red", "Blue", "Green")
    colors.forEachIndexed { index, element ->
        println("Index: $index, Element: $element")
    }
}
2
3
4
5
6
7
使用迭代器
还可以通过获取数组的迭代器来遍历元素。
fun main() {
    val colors = arrayOf("Red", "Blue", "Green")
    val iterator = colors.iterator()    // 获取数组的迭代器对象,通过迭代器对象取出数组中的元素
    while (iterator.hasNext()) {        // 判断是否有下一个元素
        val color = iterator.next()     // 取出下一个元素
        println(color)
    }
}
2
3
4
5
6
7
8
# 7.2 List
List 也是一个有序的容器,和数字很像,但是它的长度是可以变化的,所以我们可以随时添加和删除其中的元素,List主要有如下特点:
- 列表中的元素可以重复
- 列表中的元素可以修改,可以增加、修改、删除
- 列表中的元素是有序的,可以通过索引来访问
- 列表中可以存储不同数据类型的数据
# 1 创建List
创建可变的List
// 创建一个空的可变List
val list1 = mutableListOf<String>()
// 创建了一个包含三个元素的List
var list2 = mutableListOf("Doubi", "Shabi" ,"Niubi")
2
3
4
5
创建不可变List
// 创建一个包含三个整数的不可变List
val immutableList = listOf(1, 2, 3)
// 创建一个不可变的空List
val emptyList = emptyList<String>()
2
3
4
5
不可变列表不允许添加、删除或修改其中的元素。
但是一个不能添加元素的空列表有什么用呢?
有时候可能希望在某个函数中返回一个空集合作为默认值,而不是 null。这样可以避免空指针异常,并使代码更加健壮。
# 2 基础操作
# 可变和不可变转换
不可变 List 和可变 List 可以相互转换。
fun main() {
    val list1 = listOf<String>()
    val list2 = list1.toMutableList()   // 将不可变list转换为可变list
    list2.add("Doubi")
}
2
3
4
5
可以使用 List 的 toMutableList() 方法将不可变 List 转换为可变的 List。注意,原 List 不变,得到的是一个新的可变的 List。
同样,可以将可变 List 转换为 不可变 List。
fun main() {
    val list1 = mutableListOf<String>()
		val list2 = list1.toList()   				// 将可变list转换为不可变list
}
2
3
4
# 添加元素
fun main() {
    // 创建一个空的可变List
    val list = mutableListOf<String>()
    list.add("Doubi")       // 添加元素
    list += "Niubi"         // 添加元素
    println(list)           // [Doubi, Niubi]
}
2
3
4
5
6
7
除了可以使用 add() 方法添加元素,还可以使用 += 运算符添加元素。这在C++中叫运算符重载。
也可以使用 addAll 方法将其他容器中的元素全部添加到 List 中:
val list = mutableListOf<String>()
list.addAll(mutableListOf("Caibi", "Mengbi"))
2
# 获取长度
可以使用 size 属性来获取 List 的长度:
// 创建一个空的可变List
val list = mutableListOf<String>("Doubi", "Shabi", "Niubi")
println(list.size)  // 通过size属性获取长度
2
3
# 访问元素
可以使用下标来访问列表中的元素,从0开始,如果可能越界,可以使用 getOrElse 或 getOrNull 获取。
fun main() {
    // 创建一个空的可变List
    val list = mutableListOf<String>("Doubi", "Shabi", "Niubi")
    val firstElement1 = list[0]   // 通过下标来访问第一个元素
    val firstElement2 = list.first()   // 访问第一个元素
    var lastElement1 = list.last()       // 获取最后一个元素
    var lastElement2 = list[list.lastIndex]       // 通过下标获取最后一个元素
    var element1 = list.get(1)
    var element5 = list.getOrElse(5) { "Doubi" }		// 如果越界,则返回lambda的值
    var element6 = list.getOrNull(6) ?: "Doubi"     // 如果越界,返回null值,可以结合?:操作符来进行空处理
}
2
3
4
5
6
7
8
9
10
11
12
13
14
和数字的操作方式基本是一样的。
# 插入元素
可以使用 add(index, element) 方法在指定位置插入元素:
val list = mutableListOf("Doubi", "Shabi", "Niubi")
list.add(1, "Caibi")  // 在索引 1 处插入元素
println(list)   // 输出:[Doubi, Caibi, Shabi, Niubi]
2
3
也可以使用 addAll  方法插入其他的列表或集合:
val list = mutableListOf("Doubi", "Shabi", "Niubi")
list.addAll(mutableListOf("Caibi", "Jianbi"))  // 在List末尾添加另一个list中的所有元素
list.addAll(1, mutableListOf("Caibi", "Jianbi"))  // 在索引 1 处插入另一个list中的所有元素
2
3
4
# 删除元素
fun main() {
    val list = mutableListOf("Red", "Green", "Blue", "Yellow", "Pink", "Blue", "Blue")
    list.removeFirst()   		    // 删除第一个元素
    list.removeLast()   		    // 删除最后一个元素
    list.removeAt(1) 						// 按照索引删除元素
    list.remove("Blue")     		// 删除列表中所有的Blue元素
    list -= "Yellow"            // 删除Yellow元素
    println(list)
}
2
3
4
5
6
7
8
9
除了可以使用 remove 相关的方法删除,还可以使用 -= 运算符进行删除。
我们还可以使用 lambda 表达式进行判断,然后删除指定的元素。
举个栗子:
fun main() {
    val list = mutableListOf("Red", "Green", "Blue", "Yellow", "Pink", "Blue", "Blue")
    list.removeIf { it == "Blue" }      // 根据条件删除,删除所有的 Blue
    println(list)
}
2
3
4
5
在上面使用 removeIf 函数,结合 lambda 表达式,根据指定的条件删除元素。it 表示 List 中的每一个元素。
# 清空List
val list = mutableListOf("Doubi", "Shabi", "Niubi")
list.clear()
2
# 3 遍历List
遍历 List 和遍历 数组的方式是一样的。
使用 for-in 循环
可以使用 for-in 循环来遍历数组的元素。
fun main() {
    val list = mutableListOf("Red", "Green", "Blue")
    for (element in list) {   // 依次取出数组中的每个元素
        println(element)
    }
}
2
3
4
5
6
7
使用索引和 indices 属性
如果需要访问数组的索引以及元素,可以使用数组的 indices 属性,然后通过索引来访问元素。
fun main() {
    val list = mutableListOf("Red", "Green", "Blue")
    for (index in list.indices) {     // index 每个元素的索引
        println("Index: $index, Element: ${list[index]}")     // 通过索引取出每个元素
    }
}
2
3
4
5
6
7
使用 forEach 函数
Kotlin 提供了 forEach 函数,可以结合 lambda 表达式进行遍历
fun main() {
    val list = mutableListOf("Red", "Green", "Blue")
    list.forEach {
        println(it)
    }
}
2
3
4
5
6
使用 forEachIndexed 函数
如果需要同时访问索引和元素,可以使用 forEachIndexed 函数。
fun main() {
    val list = mutableListOf("Red", "Green", "Blue")
    list.forEachIndexed { index, element ->
        println("Index: $index, Element: $element")
    }
}
2
3
4
5
6
7
使用迭代器
还可以通过获取数组的迭代器来遍历元素。
fun main() {
    val list = mutableListOf("Red", "Green", "Blue")
    val iterator = list.iterator()    // 获取数组的迭代器对象,通过迭代器对象取出数组中的元素
    while (iterator.hasNext()) {        // 判断是否有下一个元素
        val color = iterator.next()     // 取出下一个元素
        println(color)
    }
}
2
3
4
5
6
7
8
9
# 4 解构
什么是解构?
解构就是用集合 List 一次性给多个变量赋值。
举个栗子:
fun main() {
    val list = mutableListOf("Red", "Green", "Blue")
    val (one, two, three) = list
    println(three)      // Blue
}
2
3
4
5
在上面的代码中,通过 List 同时给 one 、two、three 三个变量赋值。
注意,被赋值的变量要比 List 的元素少,如果比 List 的元素多会报错。
如果想取其中的某几个元素,该如何操作呢,例如 List 有5个元素,想取其中的第1个和第4个元素给变量赋值。
fun main() {
    val list = mutableListOf("Red", "Green", "Blue", "Yellow" , "Gray")
    val (str1, _, _, str2) = list
    println(str1)      // Red
    println(str2)      // Yellow
}
2
3
4
5
6
在上面的代码中,分别用第1个和第4个元素给变量 str1 和 变量 str2 赋值,忽略的元素使用 _ 占位。
# 5 其他常用操作
# 判断 List 是否为空
在 Kotlin 中,可以使用 isEmpty() 方法判断 List 是否为空,使用 isNotEmpty() 方法判断 List 是否不为空。
val numbers = mutableListOf<Int>()
if (numbers.isEmpty()) {
    println("集合为空")
}
numbers.addAll(listOf(1, 2, 3, 4, 5))
if (numbers.isNotEmpty()) {
    println("集合不为空")
}
2
3
4
5
6
7
8
9
# 检查是否包含某个元素
在 Kotlin 中,你可以使用 contains() 方法来检查是否包含某个元素。
val numbers = listOf(1, 2, 3)
println(numbers.contains(2)) // true
2
# 将 List 中的元素拼接成字符串
在 Kotlin 中,可以使用 joinToString() 函数将 List 中的元素使用指定的连接符拼接成一个字符串。
val numbers = listOf(1, 2, 3)
val numberString = numbers.joinToString(", ")
println(numberString) // 输出:1, 2, 3
2
3
# 将字符串分割成 List
在 Kotlin 中,可以使用 split() 函数将一个字符串使用指定的分隔符分割成一个 List。
val str = "1,2,3,4,5"
val list = str.split(",")
println(list) // 输出:[1, 2, 3, 4, 5]
2
3
# 使用 List 中的元素生成新的 List
在 Kotlin 中,你可以使用 map() 函数来处理 List 中的元素,然后生成一个新的 List。
val numbers = listOf(1, 2, 3)
val doubledNumbers = numbers.map { it * 2 }
println(doubledNumbers) // [2, 4, 6]
2
3
# 过滤 List 中的元素
在 Kotlin 中,可以使用 filter() 函数来过滤 List 中的元素,生成一个新的 List。
val numbers = listOf(1, 2, 3, 4, 5)
val evenNumbers = numbers.filter { it % 2 == 0 }
println(evenNumbers) // [2, 4]
2
3
在上面,通过 filter() 函数,过滤满足 it % 2 == 0 的元素,形成一个新的 List。
# 判断 List 中的元素是否有元素满足指定条件
在 Kotlin 中,可以使用 any() 函数来判断 List 中是否有元素满足指定的条件。
val numbers = listOf(1, 2, 3, 4, 5)
val f = numbers.any { it % 2 == 0 }
println(f) // true
2
3
# 判断 List 中的元素是否都满足指定条件
在 Kotlin 中,可以使用 all() 函数来判断 List 中所有的元素是否都满足指定的条件。
val numbers = listOf(1, 2, 3, 4, 5)
val f = numbers.all { it % 2 == 0 }
println(f) // false
2
3
# 7.3 Set
在 Kotlin 中,Set 与 List 有一些不同之处:Set 是一种容器类型,不允许包含重复元素,而且 Set 是无序的。Set 主要用于集合运算,例如求交集、并集、差集等。
Set 的主要特点包括:
- 不允许重复元素
- 无序,不能保证元素的顺序
- 可以被修改
- 可以存储不同的数据类型
# 1 创建 Set
创建可变的 Set 的方式,可以向其中添加或删除元素。
// 创建一个空的 Set
val emptySet = mutableSetOf<String>()
// 创建一个包含元素的 Set
val colorSet = mutableSetOf("Red", "Green", "Blue")
// 使用其他 List 或 Set 来创建
val fruits = setOf("apple", "banana", "orange").toMutableSet()
2
3
4
5
6
7
8
创建不可变的 Set 的方式,其中的元素不可修改。
// 创建一个空的 Set
val emptySet = setOf<String>()
// 创建一个包含元素的 Set
val fruits = setOf("apple", "banana", "orange")
2
3
4
5
# 2 基础操作
# 可变与不可变转换
不可变 Set 和可变 Set 可以相互转换。
将不可变 Set 转换为可变 Set:
fun main() {
    val colorSet = setOf("red", "green", "blue")
    val newColorSet = colorSet.toMutableSet()
    val newColorList = colorSet.toMutableList()
}
2
3
4
5
可以使用 Set 的 toMutableSet() 方法将不可变 Set 转换为可变的 Set。注意,原 Set 不变,得到的是一个新的可变的 Set。
甚至还可以使用 toMutableList() 方法直接转换为可变的 List。
同样,可以将可变 Set 转换为 不可变 Set 或 不可变 List。
fun main() {
    // 创建一个包含元素的 Set
    val colorSet = mutableSetOf("Red", "Green", "Blue")
    val newColorSet = colorSet.toSet()      // 得到一个新的不可变的Set
    val newColorList = colorSet.toList()    // 得到一个新的不可变的List
}
2
3
4
5
6
所以 List 和 Set 可以相互转换,还可以相互在可变和不可变之间进行转换。
所以如果我们想去掉 List 中的重复元素可以进行如下操作:
fun main() {
    val list1 = listOf<String>("red", "red", "green", "blue")
    val list2 = list1.toSet().toList()		// 先变Set再转回List
    println(list2)      // [red, green, blue]
}
2
3
4
5
可以先将有重复元素的 List 转换为 Set,然后再转换为 List。 但其实 List 有提供去重的方法,如下:
fun main() {
    val list1 = listOf<String>("red", "red", "green", "blue")
    val list2 = list1.distinct()		// 去重
    println(list2)      // [red, green, blue]
}
2
3
4
5
可以使用 distinct() 方法去掉重复的元素。
# 添加元素
可以使用 add() 、+= 、addAll() 向 Set 中添加元素:
fun main() {
    val numbers = mutableSetOf<Int>()
    numbers.add(1)      // 可以使用add方法添加元素
    numbers += 2        // 可以使用运算符来添加元素
    numbers.addAll(listOf(3, 4, 5))      // 可以使用addAll添加其他容器
}
2
3
4
5
6
# 访问元素
在 Java或其他很多语言中因为 Set 是无序的,所以无法通过下标来访问 Set 中的元素。如果要访问 Set 中的元素,只能通过迭代方式来获取。
但是 Kotlin 比较牛逼,可以使用下标来访问,真是小刀拉屁股——开眼了。
举个栗子:
fun main() {
    // 创建一个包含元素的 Set
    val colors = setOf("red", "green", "blue")
    val element1 = colors.elementAt(0)
    val element5 = colors.elementAtOrElse(5) { "black" }   // 获取index为8的元素,获取不到就使用lambda返回black
    val element6 = colors.elementAtOrNull(6) ?: "black"    // 获取index为9的元素,获取不到就返回null,结合?:操作符返回black
}
2
3
4
5
6
7
和 List 提供的方法是一样的。
那么问题来了,它是如何实现的,什么原理呢?
其实底层是使用迭代器来遍历 Set,依次取出 Set 中的元素,然后使用取出的次数当索引来返回指定的元素。

突如起来的骚气,差点闪到我的老妖。所以这个索引意义不大,和添加的顺序很可能不一致。
当然我们可以创建 LinkedHashSet ,这个是有序的 Set,那么索引就意义了。
举个栗子:
fun main() {
    // 创建可变LinkedHashSet
    val linkedHashSet1 = LinkedHashSet<String>()
    linkedHashSet1.add("red")
    linkedHashSet1.add("red")
    linkedHashSet1.add("green")
    println(linkedHashSet1)         // [red, green]
    // 创建不可变LinkedHashSet
    val linkedHashSet2 = linkedSetOf("red", "red", "green")
    println(linkedHashSet2)         // [red, green]
}
2
3
4
5
6
7
8
9
10
11
12
如果想创建有序的 Set,可以使用上面的方式来创建可变或不可变的有序 Set。
# 获取长度
你可以使用 size 属性来获取 Set 的长度:
val numbers = setOf(1, 2, 3)
println(numbers.size) // 3
2
# 删除元素
举个栗子:
fun main() {
    // 创建一个包含元素的 Set
    val colorSet = mutableSetOf("red", "green", "blue", "yellow", "gray", "black")
    colorSet.remove("red")
    colorSet -= "green"			// 使用 -= 删除
    colorSet.removeIf() { it == "blue" }				// 删除元素是blue的元素
    colorSet.removeAll(listOf("yellow", "gray"))		// 使用容器批量删除
    println(colorSet) // [black]
}
2
3
4
5
6
7
8
9
可以使用 remove 、-=  来删除,也可以使用 removeIf 通过 lambda 表达式来过滤进行删除。
还可以根据容器批量删除 Set 中的元素。
# 清空 Set
你可以使用 clear() 方法来清空 Set:
val numbers = mutableSetOf(1, 2, 3)
numbers.clear()
println(numbers) // []
2
3
# 将 Set 转换为 List
使用 toList() 方法可以将 Set 转换为 List:
val numbers = setOf(1, 2, 3)
val numList = numbers.toList()
println(numList) // [1, 2, 3]
2
3
# 3 遍历 Set
在 Kotlin 中,遍历 Set 可以使用多种方式,包括 for 循环、forEach() 方法、for-in 循环以及迭代器。以下是这些方法的示例:
使用 for-in 循环
val fruits = setOf("apple", "banana", "orange")
for (fruit in fruits) {
    println(fruit)
}
2
3
4
5
使用 forEach() 方法
val fruits = setOf("apple", "banana", "orange")
fruits.forEach { fruit ->
    println(fruit)
}
2
3
4
5
使用迭代器
val fruits = setOf("apple", "banana", "orange")
val iterator = fruits.iterator()
while (iterator.hasNext()) {
    val fruit = iterator.next()
    println(fruit)
}
2
3
4
5
6
7
使用 for 循环
因为 Set 没有索引,所以可以使用 Set.toList() 方法将 Set 转换为 List,并使用 List.size 属性确定 List 的长度,然后使用 for 循环遍历 List 中的元素。
val fruits = setOf("apple", "banana", "orange")
val fruitsList = fruits.toList()
for (i in 0 until fruitsList.size) {
    println(fruitsList[i])
}
2
3
4
5
6
# 4 其他常用操作
# 判断 Set 是否为空
可以使用 isEmpty() 方法判断 Set 是否为空,使用 isNotEmpty() 方法判断 Set 是否不为空:
val numbers = setOf<Int>()
if (numbers.isEmpty()) {
    println("Set为空")
}
val numbers2 = setOf(1, 2, 3, 4, 5)
if (numbers2.isNotEmpty()) {
    println("Set不为空")
}
2
3
4
5
6
7
8
9
# 检查是否包含某个元素
你可以使用 contains() 方法来检查 Set 是否包含某个元素:
val numbers = setOf(1, 2, 3)
println(numbers.contains(2)) // true
2
# 将 Set 中的元素拼接为字符串
可以使用 joinToString() 函数将 Set 中的元素使用指定的连接符拼接为一个字符串:
val numbers = setOf(1, 2, 3)
val numberString = numbers.joinToString(", ")
println(numberString) // "1, 2, 3"
2
3
# 使用 Set 中的元素生成新的 Set
与 List 一样,在 Kotlin 中,你可以使用 map() 方法处理 Set 中的元素,然后生成一个新的 Set:
val numbers = setOf(1, 2, 3)
val squaredNumbers = numbers.map { it * 2 }.toSet()
println(squaredNumbers) // [2, 4, 6]
2
3
Set 也提供了 filter()、any()、every() 方法,可以用来过滤、检查是否有元素满足条件以及是否所有元素都满足条件。
# 并集、交集和差集
在 Kotlin 中,Set 提供了 union()、intersect() 和 subtract() 方法,可以用来执行并集、交集和差集操作。
并集示例:
val set1 = setOf(1, 2, 3)
val set2 = setOf(3, 4, 5)
val unionSet = set1.union(set2)
println(unionSet) // [1, 2, 3, 4, 5]
2
3
4
交集示例:
val set1 = setOf(1, 2, 3)
val set2 = setOf(3, 4, 5)
val intersectionSet = set1.intersect(set2)
println(intersectionSet) // [3]
2
3
4
差集示例:
val set1 = setOf(1, 2, 3)
val set2 = setOf(3, 4, 5)
val differenceSet = set1.subtract(set2)
println(differenceSet) // [1, 2]
2
3
4
这些操作在 Kotlin 的 Set 中非常有用,可以方便地执行集合运算。
# 7.4 Map
Map是一种键值对的数据结构,其中每个键对应一个值。
例如有一份数据:
| 姓名 | 成绩 | 
|---|---|
| zhangsan | 94 | 
| lisi | 96 | 
| wangwu | 91 | 
在Kotlin中,可以使用Map来存储这种键值对数据,将姓名作为键,成绩作为值:
val studentGrades = mapOf(
    "zhangsan" to 94,
    "lisi" to 96,
    "wangwu" to 91
)
2
3
4
5
通过 to 关键字来设置 key 和 value。
这样可以很容易通过姓名键获取对应的成绩值。
# 1 创建Map
创建可变Map
// 创建一个包含元素的可变Map
val studentGrades = mutableMapOf(
    "zhangsan" to 94,
    "lisi" to 96,
    "wangwu" to 91
)
// 创建一个空可变Map
val emptyMap = mutableMapOf<String, Int>()
2
3
4
5
6
7
8
9
这种方式创建的Map是可变的(mutable),你可以随时添加、修改或删除键值对。
没有指定类型的时候,Kotlin会自动推断键和值的数据类型。
创建不可变Map
// 创建一个包含元素的不可变Map
val studentGrades = mapOf(
    "zhangsan" to 94,
    "lisi" to 96,
    "wangwu" to 91
)
// 创建一个空不可变Map
val emptyMap = emptyMap<String, Int>()
2
3
4
5
6
7
8
9
这种方式创建的Map是不可变的(immutable),意味着一旦初始化后,不能再修改其中的键值对。
其实 to 是一个函数,创建的是一个 Pair() 对象。
所以我们也可以直接创建 Pair 对象,举个栗子:
val studentGrades = mapOf(
    Pair("zhangsan", 94),
    Pair("lisi", 96),
    Pair("wangwu", 91)
)
2
3
4
5
当然了,我们一般不会这么写。
# 2 基础操作
# 添加元素
fun main() {
    val numbers = mutableMapOf<String, Int>()
    numbers["one"] = 1					// 添加或修改,会覆盖或修改之前的值
    numbers.put("one", 2)       // 添加或修改,会覆盖或修改之前的值
    numbers += "two" to 2       // 添加或修改,会覆盖或修改之前的值
    val value2 = numbers.putIfAbsent("two", 3)   // 如果key存在就不添加,并返回存在的value,如果key不存在就添加,返回null
    println(value2) // 2
    val value3 = numbers.getOrPut("three") { 4 } // 获取指定的key元素,若不存在则将该元素加入到map中,并返回value,如果存在就不添加,并返回value
    println(value3)
    println(numbers) // {one=2, two=2, three=4}
}
2
3
4
5
6
7
8
9
10
11
12
putIfAbsent 和 getOrPut 的区别:
- putIfAbsent:如果key存在就不添加,并返回存在的value,如果key不存在就添加,返回null;
- getOrPut: 获取指定的key元素,如果存在就不添加,并返回value,如果key不存在就添加,也返回value。
# 访问元素
访问元素时,通过键来访问:
fun main() {
    val numbers = mapOf(
        "one" to 1,
        "two" to 2,
        "three" to 3
    )
  
    println(numbers["one"])         // 如果key不存在,返回null
    println(numbers.get("two"))     // 如果key不存在,返回null
    println(numbers.getValue("two"))     // 如果key不存在,报错
    println(numbers.getOrDefault("two", "unknow"))     // 如果key不存在,返回defalutValue
    println(numbers.getOrElse("two") { "unknow" })   // 如果key不存在,返回lambda表达式结果
}
2
3
4
5
6
7
8
9
10
11
12
13
# 获取长度
获取Map的长度使用size属性:
val numbers = mapOf(
    "one" to 1,
    "two" to 2,
    "three" to 3
)
println(numbers.size) // 3
2
3
4
5
6
# 删除元素
删除元素通过键来进行操作:
val numbers = mutableMapOf(
    "one" to 1,
    "two" to 2,
    "three" to 3
)
numbers.remove("one")      // 删除
numbers -= "two"           // 删除
println(numbers) // {three=3}
2
3
4
5
6
7
8
9
# 清空Map
清空Map使用clear()方法:
val numbers = mutableMapOf(
    "one" to 1,
    "two" to 2,
    "three" to 3
)
numbers.clear()
println(numbers) // {}
2
3
4
5
6
7
# 3 遍历操作
在Kotlin中,遍历Map可以使用for-in循环、forEach函数、keys和values属性:
使用for-in循环
val studentGrades = mapOf(
    "Alice" to 90,
    "Bob" to 80,
    "Charlie" to 85
)
for ((key, value) in studentGrades) {
    println("$key - $value")
}
2
3
4
5
6
7
8
9
使用forEach函数
val studentGrades = mapOf(
    "Alice" to 90,
    "Bob" to 80,
    "Charlie" to 85
)
// 方式一,使用it
studentGrades.forEach {
    println("${it.key} - ${it.value}")
}
// 方式二,使用key、value
studentGrades.forEach { (key, value) ->
    println("$key - $value")
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
使用keys和values属性
val studentGrades = mapOf(
    "Alice" to 90,
    "Bob" to 80,
    "Charlie" to 85
)
for (key in studentGrades.keys) {
    val value = studentGrades[key]
    println("$key - $value")
}
for (value in studentGrades.values) {
    println("$value")
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 4 其他常用操作
# 判断Map是否为空
可以通过isEmpty()方法判断Map是否为空,通过isNotEmpty()方法判断Map是否不为空:
val numbers = emptyMap<String, Int>()
if (numbers.isEmpty()) {
    println("Map为空")
}
val studentGrades = mapOf(
    "Alice" to 90,
    "Bob" to 80,
    "Charlie" to 85
)
if (studentGrades.isNotEmpty()) {
    println("Map不为空")
}
2
3
4
5
6
7
8
9
10
11
12
13
# 检查包含某个键
val numbers = mapOf(
    "one" to 1,
    "two" to 2,
    "three" to 3
)
println(numbers.containsKey("two")) // true
2
3
4
5
6
# 检查包含某个值
val numbers = mapOf(
    "one" to 1,
    "two" to 2,
    "three" to 3
)
println(numbers.containsValue(2)) // true
2
3
4
5
6
# 获取Map中的所有键
val numbers = mapOf(
    "one" to 1,
    "two" to 2,
    "three" to 3
)
val keys = numbers.keys.toList()
println(keys) // [one, two, three]
2
3
4
5
6
7
# 将Map中的键值对拼接为字符串
val numbers = mapOf(
    "one" to 1,
    "two" to 2,
    "three" to 3
)
val numberString = numbers.entries.joinToString { (key, value) -> "$key: $value" }
println(numberString) // "one: 1, two: 2, three: 3"
2
3
4
5
6
7
