Edit Page

集合(Collection)

最终更新: 2024/03/21



第 3 步   集合(Collection)


第 5 步   函数

第 6 步  

在程序开发中, 能够将数据组织到数据结构中以供后续的处理, 这样的能力非常有用. 为了这样的目的, Kotlin 提供了集合.

Kotlin 有以下集合来组织数据元素:

集合类型 描述
List 有顺序的元素组成的集合
Set 唯一的、无顺序的元素组成的集合
Map 一组键值对(key-value pair), 其中键是唯一, 并且每个键对应到唯一的值

每个集合类型都可以是可变的, 或只读的.

List

列表按照元素添加的顺序保存它们, 而且允许重复的元素.

要创建一个只读的 List (List), 请使用 listOf() 函数.

要创建一个可变的 List (MutableList), 请使用 mutableListOf() 函数.

创建 List 时, Kotlin 可以推断它存储的元素类型. 如果要明确声明元素类型, 请在 List 的声明之后的尖括号 <> 中添加类型:

fun main() { 
//sampleStart
    // 只读 List
    val readOnlyShapes = listOf("triangle", "square", "circle")
    println(readOnlyShapes)
    // 输出结果为 [triangle, square, circle]
    
    // 可变的 List, 带有明确的类型声明
    val shapes: MutableList<String> = mutableListOf("triangle", "square", "circle")
    println(shapes)
    // 输出结果为 [triangle, square, circle]
//sampleEnd
}

为了防止无意中修改 List 的内容, 你可以将可变的 List 赋值给一个 List, 来得到它的一个只读的视图:

    val shapes: MutableList<String> = mutableListOf("triangle", "square", "circle")
    val shapesLocked: List<String> = shapes

这种操作也叫做 类型变换(casting).

List 是有顺序的, 因此要访问 List 内的元素, 请使用 下标访问操作符 []:

fun main() { 
//sampleStart
    val readOnlyShapes = listOf("triangle", "square", "circle")
    println("The first item in the list is: ${readOnlyShapes[0]}")
    // 输出结果为 The first item in the list is: triangle
//sampleEnd
}

要获取 List 中的第一个或最后一个元素, 请分别使用 .first().last() 函数:

fun main() { 
//sampleStart
    val readOnlyShapes = listOf("triangle", "square", "circle")
    println("The first item in the list is: ${readOnlyShapes.first()}")
    // 输出结果为 The first item in the list is: triangle
//sampleEnd
}

.first().last() 函数是 扩展 函数. 要对一个对象调用扩展函数, 请在对象之后加上点号 ., 然后把函数名写在后面.

关于扩展函数, 更多详情请参见 扩展函数. 对于这篇向导而言, 你只需要知道如何调用它们就行了.

要得到 List 中元素的数量, 请使用 .count() 函数:

fun main() { 
//sampleStart
    val readOnlyShapes = listOf("triangle", "square", "circle")
    println("This list has ${readOnlyShapes.count()} items")
    // 输出结果为 This list has 3 items
//sampleEnd
}

要检查一个元素是否存在于 List 中, 请使用 in 操作符:

fun main() {
//sampleStart
    val readOnlyShapes = listOf("triangle", "square", "circle")
    println("circle" in readOnlyShapes)
    // 输出结果为 true
//sampleEnd
}

要对可变 List 添加或删除元素, 请分别使用 .add().remove() 函数:

fun main() { 
//sampleStart
    val shapes: MutableList<String> = mutableListOf("triangle", "square", "circle")
    // 向 List 添加 "pentagon"
    shapes.add("pentagon") 
    println(shapes)  
    // 输出结果为 [triangle, square, circle, pentagon]

    // 从 List 中删除第一个 "pentagon" 
    shapes.remove("pentagon") 
    println(shapes)  
    // 输出结果为 [triangle, square, circle]
//sampleEnd
}

Set

List 包含有顺序的元素, 并且允许元素重复, Set 则是 无顺序的, 并且只保存 唯一的 元素.

要创建一个只读的 Set (Set), 请使用 setOf() 函数.

要创建一个可变的 Set (MutableSet), 请使用 mutableSetOf() 函数.

创建 Set 时, Kotlin 可以推断它存储的元素类型. 如果要明确声明元素类型, 请在 Set 的声明之后的尖括号 <> 中添加类型:

fun main() {
//sampleStart
    // 只读的 Set
    val readOnlyFruit = setOf("apple", "banana", "cherry", "cherry")
    // 可变的 Set, 带有明确的类型声明
    val fruit: MutableSet<String> = mutableSetOf("apple", "banana", "cherry", "cherry")
    
    println(readOnlyFruit)
    // 输出结果为 [apple, banana, cherry]
//sampleEnd
}

在上面的示例中你可以看到, 由于 Set 只包含唯一的元素, 重复的 "cherry" 元素被丢弃了.

为了防止无意中修改 Set 的内容, 你可以将可变的 Set 类型变换为 Set, 来得到它的一个只读的视图:

    val fruit: MutableSet<String> = mutableSetOf("apple", "banana", "cherry", "cherry")
    val fruitLocked: Set<String> = fruit

由于 Set 是 无顺序的, 你不能访问位于某个下标的元素.

要得到 Set 中元素的数量, 请使用 .count() 函数:

fun main() { 
//sampleStart
    val readOnlyFruit = setOf("apple", "banana", "cherry", "cherry")
    println("This set has ${readOnlyFruit.count()} items")
    // 输出结果为 This set has 3 items
//sampleEnd
}

要检查一个元素是否存在于 Set 中, 请使用 in 操作符:

fun main() {
//sampleStart
    val readOnlyFruit = setOf("apple", "banana", "cherry", "cherry")
    println("banana" in readOnlyFruit)
    // 输出结果为 true
//sampleEnd
}

要对可变 Set 添加或删除元素, 请分别使用 .add().remove() 函数:

fun main() { 
//sampleStart
    val fruit: MutableSet<String> = mutableSetOf("apple", "banana", "cherry", "cherry")
    fruit.add("dragonfruit")    // 向 Set 添加 "dragonfruit"
    println(fruit)              // 输出结果为 [apple, banana, cherry, dragonfruit]
    
    fruit.remove("dragonfruit") // 从 Set 中删除 "dragonfruit"
    println(fruit)              // 输出结果为 [apple, banana, cherry]
//sampleEnd
}

Map

Map 将元素保存为键值对(key-value pair). 你通过引用键(Key)来访问值(Value). 你可以将 Map 想象为好像一个食品菜单. 你可以通过寻找你想要吃的食物(键)来找到价格(值). 如果你想要查找一个值, 但不象 List 那样使用数字下标, 那么 Map 是很有用的.

  • Map 中的每个键必须是唯一的, 这样 Kotlin 才能懂得你想要得到哪个值.
  • 在 Map 中你可以有重复的值.

要创建一个只读的 Map (Map), 请使用 mapOf() 函数.

要创建一个可变的 Map (MutableMap), 请使用 mutableMapOf() 函数.

创建 Map 时, Kotlin 可以推断它存储的元素类型. 如果要明确声明元素类型, 请在 Map 的声明之后的尖括号 <> 中添加键和值的类型. 例如: MutableMap<String, Int>. 键的类型为 String, 值的类型为 Int.

创建 Map 的最简单的办法是在每个键和它对应的值之间使用 to :

fun main() {
//sampleStart
    // 只读 Map
    val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    println(readOnlyJuiceMenu)
    // 输出结果为 {apple=100, kiwi=190, orange=100}

    // 可变的 Map, 带有明确的类型声明
    val juiceMenu: MutableMap<String, Int> = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    println(juiceMenu)
    // 输出结果为 {apple=100, kiwi=190, orange=100}
//sampleEnd
}

为了防止无意中修改 Map 的内容, 你可以将可变的 Map 类型变换为 Map, 来得到它的一个只读的视图:

    val juiceMenu: MutableMap<String, Int> = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    val juiceMenuLocked: Map<String, Int> = juiceMenu

要访问 Map 中的值, 请使用 下标操作符 [], 以它的键为下标:

fun main() {
//sampleStart
    // 只读 Map
    val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    println("The value of apple juice is: ${readOnlyJuiceMenu["apple"]}")
    // 输出结果为 The value of apple juice is: 100
//sampleEnd
}

要得到 Map 中元素的数量, 请使用 .count() 函数:

fun main() {
//sampleStart
    // 只读 Map
    val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    println("This map has ${readOnlyJuiceMenu.count()} key-value pairs")
    // 输出结果为 This map has 3 key-value pairs
//sampleEnd
}

要对可变 Map 添加或删除元素, 请分别使用 .put().remove() 函数:

fun main() {
//sampleStart
    val juiceMenu: MutableMap<String, Int> = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    juiceMenu.put("coconut", 150) // 向 Map 添加键 "coconut" 和值 150
    println(juiceMenu)
    // 输出结果为 {apple=100, kiwi=190, orange=100, coconut=150}

    juiceMenu.remove("orange")    // 从 Map 删除键 "orange"
    println(juiceMenu)
    // 输出结果为 {apple=100, kiwi=190, coconut=150}
//sampleEnd
}

要检查一个键是否存在于 Map 中, 请使用 .containsKey() 函数:

fun main() {
//sampleStart
    val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    println(readOnlyJuiceMenu.containsKey("kiwi"))
    // 输出结果为 true
//sampleEnd
}

要得到 Map 中所有键或所有值的集合, 请分别使用 keysvalues 属性:

fun main() {
//sampleStart
    val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    println(readOnlyJuiceMenu.keys)
    // 输出结果为 [apple, kiwi, orange]
    println(readOnlyJuiceMenu.values)
    // 输出结果为 [100, 190, 100]
//sampleEnd
}

keysvalues 对象的 属性. 要访问一个对象的属性, 请在对象之后加上点号 ., 然后把属性名写在后面.

属性会在 的章节中详细介绍. 目前你只需要知道如何访问它们就行了.

要检查一个键或值是否存在于 Map 中, 请使用 in 操作符:

fun main() {
//sampleStart
    val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    println("orange" in readOnlyJuiceMenu.keys)
    // 输出结果为 true
    println(200 in readOnlyJuiceMenu.values)
    // 输出结果为 false
//sampleEnd
}

关于集合的其它更多功能, 请参见 集合.

现在你已经知道了基本类型, 以及如何管理集合, 下面我们来看看在你的程序中能够使用的 控制流.

实际练习

习题 1

你有一个 “绿色” 数字的 List, 和一个 “红色” 数字的 List. 完成下面的代码, 打印这两个 List 中总共有多少个数字.

fun main() {
    val greenNumbers = listOf(1, 4, 23)
    val redNumbers = listOf(17, 2)
    // 在这里编写你的代码
}

参考答案

fun main() {
    val greenNumbers = listOf(1, 4, 23)
    val redNumbers = listOf(17, 2)
    val totalCount = greenNumbers.count() + redNumbers.count()
    println(totalCount)
}

习题 2

你有一个 Set, 其中包含你的服务器支持的协议. 一个用户要求使用某个协议. 完成下面的程序, 检查用户要求使用的协议是否支持 (isSupported 必须是 Boolean 值).

fun main() {
    val SUPPORTED = setOf("HTTP", "HTTPS", "FTP")
    val requested = "smtp"
    val isSupported = // 在这里编写你的代码
    println("Support for $requested: $isSupported")
}

提示

请确保使用字符串的大写格式来检查请求的协议 . 你可以使用 .uppercase() 函数来帮助你实现这一点.

参考答案

fun main() {
    val SUPPORTED = setOf("HTTP", "HTTPS", "FTP")
    val requested = "smtp"
    val isSupported = requested.uppercase() in SUPPORTED
    println("Support for $requested: $isSupported")
}

习题 3

定义一个 Map, 将 1 到 3 的数字对应到它们的拼写. 使用这个 Map 来拼写指定的数字.

fun main() {
    val number2word = // 在这里编写你的代码
    val n = 2
    println("$n is spelt as '${<Write your code here >}'")
}

参考答案

fun main() {
    val number2word = mapOf(1 to "one", 2 to "two", 3 to "three")
    val n = 2
    println("$n is spelt as '${number2word[n]}'")
}

下一步

控制流