Kotlin 基础06 - List、Set、Map、Sequence

List

List、Set 和 Map 类型的变量也分为两类:只读和可变。

能修改可变列表的函数有个统一的名字:mutator 函数。

List、Set、Map、IntRange 以及其他集合都属于 Iterable,都支持遍历操作(forEach 、forEachIndexed )。

List 集合支持一种叫解构(destructuring)的语法特性,这个 Kotlin 特性允许在一个表达式里给多个变量赋值。可以通过使用 _ 符号过滤不想要的元素,有选择地从 List 集合里解构元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
val patronList = listOf("Eli", "Mordoc", "Sophie")
println(patronList)
println(patronList[0])

val ele1 = patronList.getOrElse(4) { "Unknown Patron" }
println(ele1)
val ele2 = patronList.getOrNull(4) ?: "Unknown Patron"
println(ele2)

val contains = patronList.contains("Eli")
println(contains)
val containsAll = patronList.containsAll(listOf("Sophie", "Mordoc"))
println(containsAll)

val patronList = mutableListOf("Eli", "Mordoc", "Sophie")

patronList.remove("Eli")
patronList.add("Alex")
patronList.add(0, "Alex")
patronList[3] = "Alexis"
println(patronList)

for (patron in patronList) {
println(patron)
}
patronList.forEach { patron -> println(patron) }
patronList.forEachIndexed { index, patron -> println("$index: $patron") }

val shuffled = patronList.shuffled().first()

val (goldMedal, _, bronzeMedal) = patronList

Set

Set 集合里的所有元素都具有唯一性。

Set 集合不支持基于索引的存取值函数,因为它里面的元素顺序不固定。

mutator 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
val planets = setOf("Mercury", "Venus", "Earth", "Earth")
println(planets)

val contains = planets.contains("Earth")
println(contains)

val elementAt = planets.elementAt(2)
println(elementAt)

val baseList = listOf("Eli Baggins", "Eli Baggins", "Eli Ironfoot")
val patrons = baseList.toSet().toList()
println(patrons)
val distinctList = baseList.distinct()
println(distinctList)

Map

1
2
3
4
5
6
val patronGold1 = mapOf("Eli" to 10.5, "Mordoc" to 8.0, "Sophie" to 5.5)
val patronGold2 = mutableMapOf("Eli" to 10.5, "Mordoc" to 8.0, "Sophie" to 5.5)
println(patronGold2)
patronGold2 += "Sophie" to 6.0
println(patronGold2)
println("${patronGold2["Eli"]}, ${patronGold2["Mordoc"]}, ${patronGold2["Sophie"]}, ${patronGold2[""]}")

1
2
val patronGold = mapOf("Eli" to 10.5, "Mordoc" to 8.0, "Sophie" to 5.5)
patronGold.forEach { (patron, balance) -> println("$patron, balance: ${"%.2f".format(balance)}") }

数组类型

Kotlin 提供了各种 Array 引用类型,可以编译成 Java 基本数据类型。

Kotlin 提供 Array 类型的主要目的是支持和 Java 互操作。

1
2
val arr1 = intArrayOf(34, 27, 14, 52, 101)
val arr2 = listOf(34, 27, 14, 52, 101).toIntArray()
数组类型 创建函数
IntArray intArrayOf
DoubleArray doubleArrayOf
LongArray longArrayOf
ShortArray shortArrayOf
ByteArray byteArrayOf
FloatArray floatArrayOf
BooleanArray booleanArrayOf
Array arrayOf

Array 编译为原始类型数组,其元素为引用类型。

只读与不可变

1
2
val myList = listOf(1,2,3)
(myList as MutableList)[2] = 1000

myList 被类型转换为 MutableList,因为类型转换,myList 的第三个元素被修改了。

Kotlin 不能绝对保证 List 的不可变特性。

Sequence

List、Set 以及 Map 集合类型统称为及早集合(eager collection)。这些集合的任何一个实例在创建后,它要包含的元素都会被加入并允许访问。

Kotlin 还有另外一类集合:惰性集合(lazy collection)。类似于类的惰性初始化,惰性集合类型的性能表现优异——尤其是用于包含大量元素的集合时——因为集合元素是按需产生的。

Kotlin 有个内置惰性集合类型叫序列(Sequence)。序列不会索引排序它的内容,也不记录元素数目。事实上在使用一个序列时,序列里的值可能有无限多,因为某个数据源能产生无限多个元素。

针对某个序列,定义一个只要序列有新值产生就被调用一下的函数,这样的函数叫迭代器函数(iterator function)。

可以使用 Kotlin 的序列构造函数 generateSequence 定义一个序列和它的迭代器。

generateSequence 函数接受一个初始种子值作为序列的起步值。在用 generateSequence 定义的序列上调用一个函数时,generateSequence 函数会调用指定的迭代器函数,决定下一个要产生的值。

1
2
3
4
5
6
7
8
9
10
11
fun Int.isPrime(): Boolean {
(2 until this).map {
if (this % it == 0) {
return false
}
}
return true
}

val oneThousandPrimes = generateSequence(3) { it + 1 }.filter { it.isPrime() }.take(1000)
oneThousandPrimes.forEach { println(it) }

对于包含几十万甚至上百万元素的大集合,不同集合的性能差异会很大。遇到这种情况时,可以把 List 转换为性能好的序列:

1
2
val listOfNumbers = (0 until 10000000).toList()
val sequenceOfNumbers = listOfNumbers.asSequence()

可以使用 Kotlin 的 measureNanoTime 和 measureTimeInMillis 这两个函数来测量代码执行速度。

1
2
3
4
5
6
7
8
val listInNanos = measureNanoTime {
(1..7919).toList().filter { it.isPrime() }.take(1000)
}
val sequenceInNanos = measureNanoTime {
generateSequence(3) { it + 1 }.filter { it.isPrime() }.take(1000)
}
println("List completed in $listInNanos ns")
println("Sequence completed in $sequenceInNanos ns")