Skip to content

集合

编程时,将数据分组到结构中以便后续处理非常有用。Kotlin 正是为了这个目的提供了集合。

Kotlin 提供了以下集合类型用于分组项:

集合类型描述
列表有序的项集合
无序的唯一项集合
映射键值对的集合,其中键是唯一的且只映射到一个值

每种集合类型都可以是可变的或只读的。

列表

列表按照项添加的顺序存储项,并允许重复项。

要创建一个只读列表 (List),请使用 listOf() 函数。

要创建一个可变列表 (MutableList), 请使用 mutableListOf() 函数。

创建列表时,Kotlin 可以推断存储的项的类型。要显式声明类型,请在列表声明后添加带尖括号 <> 的类型:

kotlin
fun main() { 
    // Read only list
    val readOnlyShapes = listOf("triangle", "square", "circle")
    println(readOnlyShapes)
    // [triangle, square, circle]
    
    // Mutable list with explicit type declaration
    val shapes: MutableList<String> = mutableListOf("triangle", "square", "circle")
    println(shapes)
    // [triangle, square, circle]
}

TIP

为防止意外修改,你可以通过将可变列表赋值给 List 来创建其只读视图:

kotlin

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

    val shapesLocked: List<String> = shapes

这也称为 类型转换

列表是有序的,因此要访问列表中的项,请使用索引访问操作符 []

kotlin
fun main() { 
    val readOnlyShapes = listOf("triangle", "square", "circle")
    println("The first item in the list is: ${readOnlyShapes[0]}")
    // The first item in the list is: triangle
}

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

kotlin
fun main() { 
    val readOnlyShapes = listOf("triangle", "square", "circle")
    println("The first item in the list is: ${readOnlyShapes.first()}")
    // The first item in the list is: triangle
}

NOTE

.first().last()

函数是扩展函数的示例。要在对象上调用扩展函数,请在对象名后加上一个点 . 和函数名。

扩展函数在中级教程中详细介绍。目前,你只需要知道如何调用它们。

要获取列表中的项数,请使用 .count() 函数:

kotlin
fun main() { 
    val readOnlyShapes = listOf("triangle", "square", "circle")
    println("This list has ${readOnlyShapes.count()} items")
    // This list has 3 items
}

要检查某个项是否在列表中,请使用in 操作符

kotlin
fun main() {
    val readOnlyShapes = listOf("triangle", "square", "circle")
    println("circle" in readOnlyShapes)
    // true
}

要从可变列表中添加或删除项,请分别使用 .add().remove() 函数:

kotlin
fun main() { 
    val shapes: MutableList<String> = mutableListOf("triangle", "square", "circle")
    // Add "pentagon" to the list
    shapes.add("pentagon") 
    println(shapes)  
    // [triangle, square, circle, pentagon]

    // Remove the first "pentagon" from the list
    shapes.remove("pentagon") 
    println(shapes)  
    // [triangle, square, circle]
}

列表是有序的且允许重复项,而集是无序的且只存储唯一项。

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

要创建一个可变集 (MutableSet), 请使用 mutableSetOf() 函数。

创建集时,Kotlin 可以推断存储的项的类型。要显式声明类型,请在集声明后添加带尖括号 <> 的类型:

kotlin
fun main() {
    // Read-only set
    val readOnlyFruit = setOf("apple", "banana", "cherry", "cherry")
    // Mutable set with explicit type declaration
    val fruit: MutableSet<String> = mutableSetOf("apple", "banana", "cherry", "cherry")
    
    println(readOnlyFruit)
    // [apple, banana, cherry]
}

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

TIP

为防止意外修改,你可以通过将可变集赋值给 Set 来创建其只读视图:

kotlin

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

    val fruitLocked: Set<String> = fruit

NOTE

由于集是无序的,你无法通过特定索引访问项。

要获取集中的项数,请使用 .count() 函数:

kotlin
fun main() { 
    val readOnlyFruit = setOf("apple", "banana", "cherry", "cherry")
    println("This set has ${readOnlyFruit.count()} items")
    // This set has 3 items
}

要检查某个项是否在集中,请使用in 操作符

kotlin
fun main() {
    val readOnlyFruit = setOf("apple", "banana", "cherry", "cherry")
    println("banana" in readOnlyFruit)
    // true
}

要从可变集中添加或删除项,请分别使用 .add().remove() 函数:

kotlin
fun main() { 
    val fruit: MutableSet<String> = mutableSetOf("apple", "banana", "cherry", "cherry")
    fruit.add("dragonfruit")    // Add "dragonfruit" to the set
    println(fruit)              // [apple, banana, cherry, dragonfruit]
    
    fruit.remove("dragonfruit") // Remove "dragonfruit" from the set
    println(fruit)              // [apple, banana, cherry]
}

映射

映射将项存储为键值对。你可以通过引用键来访问值。你可以将映射想象成一份食物菜单。通过查找你想吃的食物(键),你可以找到价格(值)。如果你想在不使用像列表那样编号索引的情况下查找值,映射会很有用。

NOTE

  • 映射中的每个键都必须是唯一的,这样 Kotlin 才能理解你想要获取哪个值。

  • 映射中可以有重复的值。

要创建一个只读映射 (Map),请使用 mapOf() 函数。

要创建一个可变映射 (MutableMap), 请使用 mutableMapOf() 函数。

创建映射时,Kotlin 可以推断存储的项的类型。要显式声明类型,请在映射声明后添加带尖括号 <> 的键和值类型。例如:MutableMap<String, Int>。键的类型为 String,值的类型为 Int

创建映射最简单的方法是在每个键及其相关值之间使用 to

kotlin
fun main() {
    // Read-only map
    val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    println(readOnlyJuiceMenu)
    // {apple=100, kiwi=190, orange=100}

    // Mutable map with explicit type declaration
    val juiceMenu: MutableMap<String, Int> = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    println(juiceMenu)
    // {apple=100, kiwi=190, orange=100}
}

TIP

为防止意外修改,你可以通过将可变映射赋值给 Map 来创建其只读视图:

kotlin

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

    val juiceMenuLocked: Map<String, Int> = juiceMenu

要访问映射中的值,请使用带其键的索引访问操作符 []

kotlin
fun main() {
    // Read-only 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
}

NOTE

如果你尝试使用映射中不存在的键来访问键值对,你会看到 null 值:

kotlin

fun main() {


    // Read-only map

    val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)

    println("The value of pineapple juice is: ${readOnlyJuiceMenu["pineapple"]}")

    // The value of pineapple juice is: null


}

本教程稍后会在空安全章节中解释 null 值。

你也可以使用索引访问操作符 [] 向可变映射中添加项:

kotlin
fun main() {
    val juiceMenu: MutableMap<String, Int> = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    juiceMenu["coconut"] = 150 // Add key "coconut" with value 150 to the map
    println(juiceMenu)
    // {apple=100, kiwi=190, orange=100, coconut=150}
}

要从可变映射中删除项,请使用 .remove() 函数:

kotlin
fun main() {
    val juiceMenu: MutableMap<String, Int> = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    juiceMenu.remove("orange")    // Remove key "orange" from the map
    println(juiceMenu)
    // {apple=100, kiwi=190}
}

要获取映射中的项数,请使用 .count() 函数:

kotlin
fun main() {
    // Read-only 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
}

要检查映射中是否已包含特定键,请使用 .containsKey() 函数:

kotlin
fun main() {
    val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    println(readOnlyJuiceMenu.containsKey("kiwi"))
    // true
}

要获取映射的键或值的集合,请分别使用 keysvalues 属性:

kotlin
fun main() {
    val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    println(readOnlyJuiceMenu.keys)
    // [apple, kiwi, orange]
    println(readOnlyJuiceMenu.values)
    // [100, 190, 100]
}

NOTE

keysvalues

是对象属性的示例。要访问对象的属性,请在对象名后加上一个点 . 和属性名。

属性在章节中有更详细的讨论。在本教程的这一点上,你只需要知道如何访问它们。

要检查键或值是否在映射中,请使用in 操作符

kotlin
fun main() {
    val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
    println("orange" in readOnlyJuiceMenu.keys)
    // true
    
    // Alternatively, you don't need to use the keys property
    println("orange" in readOnlyJuiceMenu)
    // true
    
    println(200 in readOnlyJuiceMenu.values)
    // false
}

有关集合可以执行的操作的更多信息,请参阅集合

既然你已经了解了基本类型以及如何管理集合,现在是时候探索可以在程序中使用的控制流了。

练习

练习 1

你有一组“绿色”数字和一组“红色”数字。补全代码以打印总共有多少个数字。

|---|---|

kotlin
fun main() {
    val greenNumbers = listOf(1, 4, 23)
    val redNumbers = listOf(17, 2)
    // Write your code here
}

|---|---|

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

练习 2

你的服务器支持一组协议。用户请求使用特定协议。补全程序以检查请求的协议是否受支持(isSupported 必须是一个布尔值)。

|---|---|

kotlin
fun main() {
    val SUPPORTED = setOf("HTTP", "HTTPS", "FTP")
    val requested = "smtp"
    val isSupported = // Write your code here 
    println("Support for $requested: $isSupported")
}

|---|---|

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

练习 3

定义一个将整数 1 到 3 关联到其对应拼写的映射。使用此映射来拼写给定的数字。

|---|---|

kotlin
fun main() {
    val number2word = // Write your code here
    val n = 2
    println("$n is spelt as '${<Write your code here >}'")
}

|---|---|

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

下一步

控制流