Kotlin 基础06 - List、Set、Map、Sequence
List
List、Set 和 Map 类型的变量也分为两类:只读和可变。
能修改可变列表的函数有个统一的名字:mutator 函数。
List、Set、Map、IntRange 以及其他集合都属于 Iterable,都支持遍历操作(forEach 、forEachIndexed )。
List 集合支持一种叫解构(destructuring)的语法特性,这个 Kotlin 特性允许在一个表达式里给多个变量赋值。可以通过使用 _
符号过滤不想要的元素,有选择地从 List 集合里解构元素。
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 函数
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
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[""]}")
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 互操作。
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 编译为原始类型数组,其元素为引用类型。
只读与不可变
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 函数会调用指定的迭代器函数,决定下一个要产生的值。
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 转换为性能好的序列:
val listOfNumbers = (0 until 10000000).toList()
val sequenceOfNumbers = listOfNumbers.asSequence()
可以使用 Kotlin 的 measureNanoTime 和 measureTimeInMillis 这两个函数来测量代码执行速度。
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")