跳到主要内容

集合

在编程中,能够将数据分组到结构中以便后续处理非常有用。Kotlin 提供了集合 (collections) 正是为此目的。

Kotlin 提供了以下集合 (collections) 类型用于对条目进行分组:

集合类型 (Collection type)描述 (Description)
列表 (Lists)条目的有序集合 (Ordered collections of items)
集合 (Sets)唯一条目的无序集合 (Unique unordered collections of items)
映射 (Maps)键值对的集合,其中键是唯一的,并且仅映射到一个值 (Sets of key-value pairs where keys are unique and map to only one value)

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

列表 (List)

列表 (Lists) 按照添加的顺序存储条目,并允许重复条目。

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

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

创建列表时,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]

}
备注

为了防止不必要的修改,你可以通过将可变列表赋值给 List 来创建可变列表的只读视图:

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

这也称为类型转换 (casting)

列表 (Lists) 是有序的,因此要访问列表中的条目,请使用索引访问操作符 (indexed access operator) []

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() 函数:

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

}

.first().last() 函数是扩展 (extension) 函数的示例。要在对象上调用扩展 (extension) 函数,请在对象后加上句点 . 后写入函数名称。

有关扩展 (extension) 函数的更多信息,请参见扩展函数 (Extension functions)。就本教程而言,你只需要知道如何调用它们。

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

fun main() { 

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

}

要检查某个条目是否在列表中,请使用 in 运算符

fun main() {

val readOnlyShapes = listOf("triangle", "square", "circle")
println("circle" in readOnlyShapes)
// true

}

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

fun main() { 

val shapes: MutableList<String> = mutableListOf("triangle", "square", "circle")
// 将 "pentagon" 添加到列表中 (Add "pentagon" to the list)
shapes.add("pentagon")
println(shapes)
// [triangle, square, circle, pentagon]

// 从列表中删除第一个 "pentagon" (Remove the first "pentagon" from the list)
shapes.remove("pentagon")
println(shapes)
// [triangle, square, circle]

}

集合 (Set)

列表 (lists) 是有序的并允许重复的条目,而集合 (sets) 是无序的,并且仅存储唯一的条目。

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

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

创建集合时,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" 条目被删除。

备注

为了防止不必要的修改,你可以通过将可变集合 (mutable set) 分配给 Set 来创建可变集合 (mutable set) 的只读视图:

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

由于集合 (sets) 是无序的,因此无法访问特定索引处的项目。

要获取集合 (set) 中条目的数量,请使用 .count() 函数:

fun main() { 

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

}

要检查集合 (set) 中是否存在某个条目,请使用 in 运算符

fun main() {

val readOnlyFruit = setOf("apple", "banana", "cherry", "cherry")
println("banana" in readOnlyFruit)
// true

}

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

fun main() { 

val fruit: MutableSet<String> = mutableSetOf("apple", "banana", "cherry", "cherry")
fruit.add("dragonfruit") // 将 "dragonfruit" 添加到集合 (Add "dragonfruit" to the set)
println(fruit) // [apple, banana, cherry, dragonfruit]

fruit.remove("dragonfruit") // 从集合 (set) 中删除 "dragonfruit" (Remove "dragonfruit" from the set)
println(fruit) // [apple, banana, cherry]

}

映射 (Map)

映射 (Maps) 将条目存储为键值对 (key-value pairs)。你可以通过引用键 (key) 来访问值 (value)。你可以将映射 (map) 想象成食物菜单。你可以通过找到你想吃的食物(键 (key))来找到价格(值 (value))。如果你想在不使用编号索引(如列表 (list) 中)的情况下查找值 (value),则映射 (maps) 非常有用。

备注
  • 映射 (map) 中的每个键 (key) 都必须是唯一的,这样 Kotlin 才能理解你要获取哪个值 (value)。
  • 你可以在映射 (map) 中包含重复的值 (value)。

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

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

创建映射 (maps) 时,Kotlin 可以推断存储的条目的类型。要显式声明类型,请在映射声明后的尖括号 <> 中添加键 (key) 和值 (value) 的类型。例如:MutableMap<String, Int>。键 (keys) 的类型为 String,值 (values) 的类型为 Int

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

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}

}
备注

为了防止不必要的修改,你可以通过将可变映射 (mutable map) 赋值给 Map 来创建可变映射 (mutable map) 的只读视图:

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

要访问映射 (map) 中的值 (value),请使用带有其键 (key) 的索引访问操作符 (indexed access operator) []

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

}

如果你尝试使用映射 (map) 中不存在的键 (key) 访问键值对 (key-value pair),你将看到一个 null 值 (value):

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 safety) 章节中稍后解释空值 (null values)。

你还可以使用索引访问操作符 (indexed access operator) [] 将条目添加到可变映射 (mutable map):

fun main() {

val juiceMenu: MutableMap<String, Int> = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
juiceMenu["coconut"] = 150 // 将键 "coconut" 以及值 150 添加到映射 (map)
println(juiceMenu)
// {apple=100, kiwi=190, orange=100, coconut=150}

}

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

fun main() {

val juiceMenu: MutableMap<String, Int> = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
juiceMenu.remove("orange") // 从映射 (map) 中删除键 "orange" (Remove key "orange" from the map)
println(juiceMenu)
// {apple=100, kiwi=190}

}

要获取映射 (map) 中条目的数量,请使用 .count() 函数:

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

}

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

fun main() {

val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
println(readOnlyJuiceMenu.containsKey("kiwi"))
// true

}

要获取映射 (map) 的键 (keys) 或值 (values) 的集合 (collection),请分别使用 keysvalues 属性:

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]

}
备注

keysvalues 是对象的属性 (properties) 的示例。要访问对象的属性 (property),请在对象后附加一个句点 . 后写入属性 (property) 名称。

属性 (properties) 将在类 (Classes) 章节中进行更详细的讨论。在本教程的这一点上,你只需要知道如何访问它们。

要检查映射 (map) 中是否存在键 (key) 或值 (value),请使用 in 运算符

fun main() {

val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100)
println("orange" in readOnlyJuiceMenu.keys)
// true

// 或者,你不需要使用 keys 属性 (property)
println("orange" in readOnlyJuiceMenu)
// true

println(200 in readOnlyJuiceMenu.values)
// false

}

有关你可以使用集合 (collections) 执行的更多操作的信息,请参见 集合 (Collections)

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

练习 (Practice)

练习 1 (Exercise 1)

你有一个“绿色 (green)”数字列表和一个“红色 (red)”数字列表。完成代码以打印总共有多少个数字。

|---|---|

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

|---|---|

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

练习 2 (Exercise 2)

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

|---|---|

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

提示 (Hint)

确保你以大写形式检查请求的协议 (protocol)。你可以使用 .uppercase() 函数来帮助你。

|---|---|

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

练习 3 (Exercise 3)

定义一个映射 (map),将从 1 到 3 的整数数字与其对应的拼写相关联。使用此映射 (map) 来拼写给定的数字。

|---|---|

fun main() {
val number2word = // 在这里写你的代码 (Write your code here)
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]}'")
}

下一步 (Next step)

控制流 (Control flow)