集合概念
Kotlin 100%与Java互操作,所以Java中集合在Kotlin同样可以使用,如大家熟悉的ArrayList、HashMap、Set等。
Kotlin中三种基本的容器分别为Set、Map、List。
三种容器有一些共同的方法:
- isEmpty 判定容器是否为空
- isNotEmpty 判断容器是否非空
- clear 清空容器
- contains 是否包含指定元素
集合类型
每种容器又分为只读与可变两者类型,只读没有add、remove等操作方法,可变类型具有这些操作方法,这在概念上就将读写进行了分离。
- 一个 只读 接口,提供访问集合元素的操作。
- 一个 可变 接口,通过写操作扩展相应的只读接口:添加、删除及更新其元素。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oH3IiSsO-1664162428764)(http://192.168.120.239:4999/server/index.php?s=/api/attachment/visitFile/sign/f288c8f776d830bfec66de626c752837 “集合的类继承关系图”)]
Collection<T> 是集合层次结构的根,表示只读集合的共同行为:检索大小、 检测是否为成员等等。 Collection 继承自 Iterable <T> 接口,它定义了迭代元素的操作。可以使用 Collection 作为适用于不同集合类型的函数的参数。 MutableCollection<T> 是一个具有写操作的 Collection 接口,例如 add 以及 remove 。
List
- 按顺序存储元素,通过索引读取元素。
- 只读类型
List<T> ,可变类型MutableList<T> 。 - 同数组(Array)类似,但是Array初始化定义,不会变,List没有预设大小,可通过Add、remove等方法更新。
- 默认实现ArrayList。
List 可包含空值,可重复,可相等。
Set
- 存储顺序不按顺序。
- 只读类型
Set<T> ,可变类型MutableSet 。 - 一个 Set 只能包含一个 null。
- 大小和元素都相同时候则相等。
Map
- 存储键值对,不是
Collection 接口的继承者。 - 只读类型
Map<K, V> ,可变类型MutableMap 。 - 键是唯一的,但是不同的键可以与相同的值配对。
Map 接口提供特定的函数进行通过键访问值、搜索键和值等操作。- 大小和键值完全相同的两个Map相等。
- 默认实现
LinkedHashMap ,保证顺序,HashMap 不保证顺序。
初始化方法
使用库函数初始化
使用listOf 、mutableListOf 函数初始化,其中listOf 创建的是只读集合,mutableListOf 创建的是可变集合。
//创建只读列表
val numbers = listOf("one", "two", "three", "four")
//创建可变列表
val mutableNumbers = mutableListOf("one", "two", "three", "four")
set 、map 初始化与上面类似。 val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1) 考虑map性能时候使用如下写法 val numbersMap = mutableMapOf<String, String>().apply { this["one"] = "1"; this["two"] = "2" }
使用构造器函数初始化
使用下列形式的构造函数 buildList() , buildSet() , 或者 buildMap() 示例代码:
val map = buildMap {
put("a", 1)
put("b", 0)
put("c", 4)
}
println(map)
空集合
没有任何元素的集合emptyList() 、 emptySet() 与 emptyMap() 。
List初始化
传入大小及初始化函数
val doubled = List(3, { it * 2 })
println(doubled)
具体类型构造函数
针对ArrayList 、LinkedList 、HashMap 的初始化
val linkedList = LinkedList<String>(listOf("one", "two", "three"))
val presizedSet = HashSet<Int>(32)
复制初始化
-使用复制函数创建一个新的集合,例如toList() 、 toMutableList() 、 toSet() 等等
val alice = Person("Alice")
val sourceList = mutableListOf(alice, Person("Bob"))
val copyList = sourceList.toList()
sourceList.add(Person("Charles"))
-不同类型之间的转换
val sourceList = mutableListOf(1, 2, 3)
val copySet = sourceList.toMutableSet()
-创建对同一集合实例的新引用
val sourceList = mutableListOf(1, 2, 3)
val referenceList = sourceList
调用其他集合的函数
可以通过其他集合各种操作的结果来创建集合。 例如调用filter 函数创建新的集合
val numbers = listOf("one", "two", "three", "four")
val longerThan3 = numbers.filter { it.length > 3 }
迭代器
用于遍历集合,同Java的迭代器概念一致。
val numbers = listOf("one", "two", "three", "four")
val numbersIterator = numbers.iterator()
while (numbersIterator.hasNext()) {
println(numbersIterator.next())
}
使用for 遍历
val numbers = listOf("one", "two", "three", "four")
for (item in numbers) {
println(item)
}
使用forEach 遍历
val numbers = listOf("one", "two", "three", "four")
numbers.forEach {
println(it)
}
List迭代器
对于列表,有一个特殊的迭代器实现: ListIterator 。 它支持列表双向迭代:正向与反向。反向迭代由 hasPrevious() 与 previous() 函数实现。通过 nextIndex() 与 previousIndex() 函数提供有关元素索引的信息
val numbers = listOf("one", "two", "three", "four")
val listIterator = numbers.listIterator()
while (listIterator.hasNext()) listIterator.next()
println("Iterating backwards:")
while (listIterator.hasPrevious()) {
print("Index: ${listIterator.previousIndex()}")
println(", value: ${listIterator.previous()}")
}
可变迭代器
为了迭代可变集合,于是有了 MutableIterator 来扩展 Iterator 使其具有元素删除函数 remove() ,也可插入与替换。
val numbers = mutableListOf("one", "two", "three", "four")
val mutableIterator = numbers.iterator()
mutableIterator.next()
mutableIterator.remove()
mutableListIterator.add("two")
mutableListIterator.next()
mutableListIterator.set("three")
println("After removal: $numbers")
区间与数列
Kotlin中区间使用 rangeTo() 函数及其操作符形式的 .. 来表示。通常,rangeTo() 会辅以 in 或 !in 函数。 区间使用示例: 用于条件判定
val i = 1
//sampleStart
if (i in 1..4) { // 等同于 1 <= i && i <= 4
print(i)
}
用于遍历
for (i in 1..4) print(i)
反向迭代 反向迭代数字,请使用 downTo
for (i in 4 downTo 1) print(i)
也可以通过任意步长(不一定为 1 )迭代数字,使用step 函数
for (i in 1..8 step 2) print(i)
println()
for (i in 8 downTo 1 step 2) print(i)
不包含其结束元素的数字区间,使用until
for (i in 1 until 10) { // i in 1 到 10, 不含 10
print(i)
}
区间
定义:有端点的封闭的间隔,为比较类型定义,有顺序。 举个版本号比较的例子
class Version(val major: Int, val minor: Int): Comparable<Version> {
override fun compareTo(other: Version): Int {
if (this.major != other.major) {
return this.major - other.major
}
return this.minor - other.minor
}
}
//使用
val versionRange = Version(1, 11)..Version(1, 30)
println(Version(0, 9) in versionRange)
println(Version(1, 20) in versionRange)
数列
整数区间的等差数列,包含类型Int 、Long 与 Char 。在 Kotlin 中,这些数列由特殊类型定义:IntProgression 、 LongProgression 与 CharProgression 。 数列具有三个基本属性:first 元素、last 元素和一个非零的 step。
for (int i = first; i <= last; i += step) {
// ……
}
step为1 for (i in 1..10) print(i)
step为其他值
for (i in 1..8 step 2) print(i)
数列的 last 元素是这样计算的:
- 对于正步长:不大于结束值且满足 (last - first) % step == 0 的最大值。
- 对于负步长:不小于结束值且满足 (last - first) % step == 0 的最小值。
因此,last 元素并非总与指定的结束值相同。
for (i in 1..9 step 3) print(i) // 最后一个元素是 7
反向数列使用downTo
for (i in 4 downTo 1) print(i)
也可使用取反函数
for (i in (1..4).reversed()) print(i)
数列也实现了迭代器接口Iterable<N> ,其中 N 分别是 Int、Long 或 Char,各种集合函数,例如map 、filter 等也使用于数列。
println((1..10).filter { it % 2 == 0 })
序列
序列(Sequence<T>) 提供与 Iterable 相同的函数。 区别:
Iterable 按顺序执行每个函数,然后生成中间结果传递给下个函数,Sequence 有点懒执行的味道,仅当整个处理链的结果时才进行实际计算。- Sequence 对每个元素逐个执行所有处理步骤;Iterable 完成整个集合的每个步骤,然后进行下一步。
- Sequence避免生成中间结果,提升性能, 但是其惰性性质增加了一些开销,这些开销在处理较小的集合或进行更简单的计算时可能很重要。
总结
少量数据使用Iterable ,大量数据使用Sequence
构造
由元素
val numbersSequence = sequenceOf("four", "three", "two", "one")
由 Iterable
val numbers = listOf("one", "two", "three", "four")
val numbersSequence = numbers.asSequence()
由函数
val oddNumbers = generateSequence(1) { it + 2 } // `it` 是上一个元素
println(oddNumbers.take(5).toList())
//println(oddNumbers.count()) // 错误:此序列是无限的。
创建有限序列
//最后一个元素之后返回null
val oddNumbersLessThan10 = generateSequence(1) { if (it < 8) it + 2 else null }
println(oddNumbersLessThan10.count())
由块函数 由sequence() 函数。 此函数采用一个 lambda 表达式,其中包含 yield() 与yieldAll() 函数的调用。 它们将一个元素返回给序列使用者,并暂停 sequence() 的执行,直到使用者请求下一个元素。 yield() 使用单个元素作为参数;yieldAll() 中可以采用 Iterable 对象、 Iterator 或其他 Sequence 。yieldAll() 的 Sequence 参数可以是无限的。 当然,这样的调用必须是最后一个: 之后的所有调用都永远不会执行。
val oddNumbers = sequence {
yield(1)
yieldAll(listOf(3, 5))
yieldAll(generateSequence(7) { it + 2 })
}
println(oddNumbers.take(5).toList())
序列操作
分类如下:
- 无状态 操作不需要状态,并且可以独立处理每个元素,例如
map() 或 filter() 。 无状态操作还可能需要少量常数个状态来处理元素,例如 take() 与 drop() 。 - 有状态 操作需要大量状态,通常与序列中元素的数量成比例。
如果序列操作返回延迟生成的另一个序列,则称为 中间序列。 否则,该操作为 末端操作。 末端操作的示例为 toList() 或 sum() 。只能通过末端操作才能检索序列元素。 序列可以多次迭代;但是,某些序列实现可能会约束自己仅迭代一次。
序列与迭代器直观比较
下面举个过滤单词的例子看 Iterable 与 Sequence 之间的区别 假定有一个单词列表。下面的代码过滤长于三个字符的单词,并输出前四个单词的长度。 Iterable 代码示例
val words = "The quick brown fox jumps over the lazy dog".split(" ")
val lengthsList = words.filter { println("filter: $it"); it.length > 3 }
.map { println("length: ${it.length}"); it.length }
.take(4)
println("Lengths of first 4 words longer than 3 chars:")
println(lengthsList)
处理流程图 
Sequence 代码示例
val words = "The quick brown fox jumps over the lazy dog".split(" ")
// 将列表转换为序列
val wordsSequence = words.asSequence()
val lengthsSequence = wordsSequence.filter { println("filter: $it"); it.length > 3 }
.map { println("length: ${it.length}"); it.length }
.take(4)
println("Lengths of first 4 words longer than 3 chars")
// 末端操作:以列表形式获取结果。
println(lengthsSequence.toList())
处理流程图 
在此示例中,序列处理需要 18 个步骤,而不是 23 个步骤来执行列表操作。
集合操作
集合操作包括简单的获取、添加、删除,复杂的过滤、搜索、排序、分组、转换。
集合操作在标准库中以两种方式声明:集合接口的成员函数和扩展函数。 成员函数如isEmpty() ,get() 等 扩展函数如filter 、sort 、groupBy 等
公共操作可用于只读集合与可变集合。 公共操作分为以下几类:
- 集合转换
- 集合过滤
- plus 与 minus 操作符
- 分组
- 取集合的一部分
- 取单个元素
- 集合排序
- 集合聚合操作
这些页面中描述的操作将返回其结果,而不会影响原始集合。
val numbers = listOf("one", "two", "three", "four")
numbers.filter { it.length > 3 } // `numbers` 没有任何改变,结果丢失
println("numbers are still $numbers")
val longerThan3 = numbers.filter { it.length > 3 } // 结果存储在 `longerThan3` 中
println("numbers longer than 3 chars are $longerThan3")
将目标集合作为附加参数
例如用 filterTo() 代替 filter() 以及用 associateTo() 代替 associate()
val numbers = listOf("one", "two", "three", "four")
val filterResults = mutableListOf<String>() // 目标对象
numbers.filterTo(filterResults) { it.length > 3 }
numbers.filterIndexedTo(filterResults) { index, _ -> index == 0 }
println(filterResults) // 包含两个操作的结果
// 将数字直接过滤到新的哈希集中,从而消除结果中的重复项
val result = numbers.mapTo(HashSet()) { it.length }
写操作
写操作针对可变结合,包括添加、删除和更新元素,及排序等。写操作在集合写操作以及 List 写操作与 Map 写操作的相应部分中列出。 对于某些操作,有成对的函数可以执行相同的操作:一个函数就地应用该操作, 另一个函数将结果作为单独的集合返回。例如sort() 和sorted() .
val numbers = mutableListOf("one", "two", "three", "four")
val sortedNumbers = numbers.sorted() //生成了新的容器
println(numbers == sortedNumbers) // false
numbers.sort() //还是原来的容器,只是状态变化了
println(numbers == sortedNumbers) // true
映射
映射 转换从另一个集合的元素上的函数结果创建一个集合。
val numbers = setOf(1, 2, 3)
println(numbers.map { it * 3 })
println(numbers.mapIndexed { idx, value -> value * idx })
合拢
合拢 转换是根据两个集合中具有相同位置的元素构建配对。
val colors = listOf("red", "brown", "grey")
val animals = listOf("fox", "bear", "wolf")
println(colors zip animals)
val twoAnimals = listOf("fox", "bear")
println(colors.zip(twoAnimals))
也可以使用带有两个参数的转换函数来调用 zip()
val colors = listOf("red", "brown", "grey")
val animals = listOf("fox", "bear", "wolf")
println(colors.zip(animals) { color, animal -> "The ${animal.replaceFirstChar { it.uppercase() }} is $color"})
要分割键值对列表,请调用 unzip()
val numberPairs = listOf("one" to 1, "two" to 2, "three" to 3, "four" to 4)
println(numberPairs.unzip())
关联
关联 转换允许从集合元素和与其关联的某些值构建 Map。
val numbers = listOf("one", "two", "three", "four")
println(numbers.associateWith { it.length })
展平
如需操作嵌套的集合,那么可能会发现提供对嵌套集合元素进行打平访问的标准库函数很有用。
val numberSets = listOf(setOf(1, 2, 3), setOf(4, 5, 6), setOf(1, 2))
println(numberSets.flatten())
另一个函数——flatMap() ,flatMap() 表现为 map() (以集合作为映射结果)与 flatten() 的连续调用。
val containers = listOf(
StringContainer(listOf("one", "two", "three")),
StringContainer(listOf("four", "five", "six")),
StringContainer(listOf("seven", "eight"))
)
//先取出`StringContainer`的values,然后再flatten操作
println(containers.flatMap { it.values })
转字符串
以可读格式检索集合,使用joinToString() 与 joinTo() 。 joinToString() 根据提供的参数从集合生成String , joinTo() 提供相同的操作,但是将结果给指定的 Appendable 对象。
val numbers = listOf("one", "two", "three", "four")
println(numbers)
println(numbers.joinToString())
val listString = StringBuffer("The list of numbers: ")
//接收者作为参数传入
numbers.joinTo(listString)
println(listString)
指定joinToString 参数,生成指定规则的String
val numbers = listOf("one", "two", "three", "four")
println(numbers.joinToString(separator = " | ", prefix = "start: ", postfix = ": end"))
大集合使用limit 限制,超出的使用省略号替代truncated
val numbers = (1..100).toList()
//只生成前10个元素的字符串,超出部分用`<...>`代替
println(numbers.joinToString(limit = 10, truncated = "<...>"))
定义元素形式本生使用transform 函数
val numbers = listOf("one", "two", "three", "four")
println(numbers.joinToString { "Element: ${it.uppercase()}"})
过滤
过滤分为一般filter过滤、划分、检验谓词
filter过滤
使用lambda形式的表达式filter ,根据Boolean值结果返回true或者false进行过滤。
val numbers = listOf("one", "two", "three", "four")
val longerThan3 = numbers.filter { it.length > 3 }
println(longerThan3)
// filterIndexed(),带有元素索引和元素值
val filteredIdx = numbers.filterIndexed { index, s -> (index != 0) && (s.length < 5) }
//否定条件来过滤, 那就是长度大于3的元素
val filteredNot = numbers.filterNot { it.length <= 3 }
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
val filteredMap = numbersMap.filter { (key, value) -> key.endsWith("1") && value > 10}
过滤指定类型使用filterIsInstance() 过滤不为空的filterNotNull()
val numbers = listOf(null, 1, "two", 3.0, "four")
//过滤出String类型的元素
numbers.filterIsInstance<String>().forEach {
println(it.uppercase())
}
//过滤掉空元素
numbers.filterNotNull().forEach {
println(it.length) // 对可空的 String 来说长度不可用
}
划分
使用 partition() , 满足条件的放到一个List,不满足的放到另外个List,返回值是一个Pair类型的值。
val numbers = listOf("one", "two", "three", "four")
val (match, rest) = numbers.partition { it.length > 3 }
检验谓词
- 如果至少有一个元素匹配给定谓词,那么 any() 返回 true。
- 如果没有元素与给定谓词匹配,那么 none() 返回 true。
- 如果所有元素都匹配给定谓词,那么 all() 返回 true。 请注意,在一个空集合上使用任何有效的谓词去调用 all() 都会返回 true 。这种行为在逻辑上被称为 vacuous truth。
val numbers = listOf("one", "two", "three", "four")
println(numbers.any { it.endsWith("e") })
println(numbers.none { it.endsWith("a") })
println(numbers.all { it.endsWith("e") })
println(emptyList<Int>().all { it > 5 })
加减操作
集合定义了 plus (+) 和 minus (-) 操作符。第一个操作数为集合,第二个操作数为集合或者元素。
val numbers = listOf("one", "two", "three", "four")
val plusList = numbers + "five"
val minusList = numbers - listOf("three", "four")
map的加减操作参考map章节,集合还定义了广义赋值操作符 plusAssign (+=) 与 minusAssign (-=) 。
分组操作
使用函数 groupBy() 进行分组操作,使用一个 lambda 函数并返回一个 Map。
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.groupBy { it.first().uppercase() })
println(numbers.groupBy(keySelector = { it.first() }, valueTransform = { it.uppercase() }))
如果要对元素进行分组,然后一次将操作应用于所有分组,请使用 groupingBy() 函数。 Grouping 支持以下操作:
eachCount() 计算每个组中的元素。 fold() 与 reduce() 对每个组分别执行 fold 与 reduce 操作,作为一个单独的集合并返回结果。 aggregate() 随后将给定操作应用于每个组中的所有元素并返回结果。 这是对 Grouping 执行任何操作的通用方法。当折叠或缩小不够时,可使用它来实现自定义操作。
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.groupingBy { it.first() }.eachCount())
获取部分集合
slice
slice() 返回具有给定索引的集合元素列表。
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.slice(1..3))
println(numbers.slice(0..4 step 2))
println(numbers.slice(setOf(3, 5, 0)))
take 与 drop
从开头获取使用take() 函数,从结尾获取使用 takeLast() 函数。 要从头或从尾去除给定数量的元素,请调用 drop() 或 dropLast() 函数。
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.take(3))
println(numbers.takeLast(3))
println(numbers.drop(1))
println(numbers.dropLast(5))
还有takeWhile() ,takeLastWhile() ,dropWhile() ,dropLastWhile() 等函数
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.takeWhile { !it.startsWith('f') })
println(numbers.takeLastWhile { it != "three" })
println(numbers.dropWhile { it.length == 3 })
println(numbers.dropLastWhile { it.contains('i') })
chunked
要将集合分解为给定大小的“块”,请使用 chunked() 函数。
val numbers = (0..13).toList()
println(numbers.chunked(3))
println(numbers.chunked(3) { it.sum() })
windowed
可以检索给定大小的集合元素中所有可能区间,函数称为 windowed() 。
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.windowed(3))
执行结果:
[[one, two, three], [two, three, four], [three, four, five]]
windowed() 提供可选参数
val numbers = (1..10).toList()
println(numbers.windowed(3, step = 2, partialWindows = true))
println(numbers.windowed(3) { it.sum() })
执行结果:
[[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9], [9, 10]]
[6, 9, 12, 15, 18, 21, 24, 27]
要构建两个元素的窗口,有一个单独的函数——zipWithNext()
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.zipWithNext())
println(numbers.zipWithNext() { s1, s2 -> s1.length > s2.length})
执行结果:
[(one, two), (two, three), (three, four), (four, five)]
[false, false, true, false]
获取单个元素
list是有序的,可通过索引获取单个元素,set是无序的,但是一些子类实现是有序的。例如LinkedHashSet 或者SortedSet 。 使用elementAt() 获取指定位置元素 如果是List,则使用索引访问操作符 (get() 或 [])更为习惯。
检索第一个和最后一个元素分别使用first() 和last() 函数。
为了避免获取元素出现异常,提供了elementAtOrNull() 、elementAtOrElse() 等函数。
示例代码
val numbers = linkedSetOf("one", "two", "three", "four", "five")
println(numbers.elementAt(3))
val numbersSortedSet = sortedSetOf("one", "two", "three", "four")
println(numbersSortedSet.elementAt(0))
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.first())
println(numbers.last())
println(numbers.elementAtOrNull(5))
println(numbers.elementAtOrElse(5) { index -> "The value for index $index is undefined"})
按条件获取
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.first { it.length > 3 })
println(numbers.last { it.startsWith("f") })
println(numbers.firstOrNull { it.length > 6 })
使用find() 及findLast() 函数
val numbers = listOf(1, 2, 3, 4)
println(numbers.find { it % 2 == 0 })
println(numbers.findLast { it % 2 == 0 })
选择器检索
val list = listOf<Any>(0, "true", false)
val longEnough = list.firstNotNullOf { item -> item.toString().takeIf { it.length >= 4 } }
println(longEnough)
随机取元素
使用random() 函数,如果是空集合则使用randomOrNull() ,避免抛出异常。
val numbers = listOf(1, 2, 3, 4)
println(numbers.random())
检测元素存在与否
检查是否存在使用 contains() 、equals() 、containsAll() 等函数 检查是否为null使用isEmpty() 和 isNotEmpty() 等函数
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.contains("four"))
println("zero" in numbers)
println(numbers.containsAll(listOf("four", "two")))
println(numbers.isEmpty())
println(numbers.isNotEmpty())
排序
自然排序:数值大小比较、字母顺序 自定义排序:需要实现Comparable 接口的compareTo() 方法
自然排序
val numbers = listOf("one", "two", "three", "four")
println("Sorted ascending: ${numbers.sorted()}")
println("Sorted descending: ${numbers.sortedDescending()}")
自定义排序
val lengthComparator = Comparator { str1: String, str2: String -> str1.length - str2.length }
println(listOf("aaa", "bb", "c").sortedWith(lengthComparator))
println(listOf("aaa", "bb", "c").sortedWith(compareBy { it.length }))
val numbers = listOf("one", "two", "three", "four")
val sortedNumbers = numbers.sortedBy { it.length }
println("Sorted by length ascending: $sortedNumbers")
val sortedByLast = numbers.sortedByDescending { it.last() }
println("Sorted by the last letter descending: $sortedByLast")
倒序
reversed() 返回带有元素副本的新集合。 asReversed() 返回相同集合实例的一个反向视图,不会生成副本。 如果原始列表只读,那么使用asReversed() 更轻量。
val numbers = listOf("one", "two", "three", "four")
val reversedNumbers = numbers.asReversed()
println(reversedNumbers)
val mnumbers = mutableListOf("one", "two", "three", "four")
val mreversedNumbers = mnumbers.asReversed()
println(mreversedNumbers)
mnumbers.add("five")
println(mreversedNumbers)
随机顺序
shuffled() 函数返回一个包含了以随机顺序排序的集合元素的新的 List。
val numbers = listOf("one", "two", "three", "four")
println(numbers.shuffled())
聚合操作
通用操作
常用的聚合操作函数如下:
minOrNull() 与 maxOrNull() 分别返回最小和最大的元素。 空集合返回空。average() 返回数字集合中元素的平均值。sum() 返回数字集合中元素的总和。count() 返回集合中元素的数量。 示例代码:
val numbers = listOf(6, 42, 10, 4)
println("Count: ${numbers.count()}")
println("Max: ${numbers.maxOrNull()}")
println("Min: ${numbers.minOrNull()}")
println("Average: ${numbers.average()}")
println("Sum: ${numbers.sum()}")
还有其他一些函数: maxByOrNull() 与 minByOrNull() maxWithOrNull() 与 minWithOrNull() maxOfOrNull() and minOfOrNull() maxOfWithOrNull() and minOfWithOrNull() 示例代码:
val numbers = listOf(5, 42, 10, 4)
val min3Remainder = numbers.minByOrNull { it % 3 }
println(min3Remainder)
val strings = listOf("one", "two", "three", "four")
val longestString = strings.maxWithOrNull(compareBy { it.length })
println(longestString)
println(numbers.sumOf { it * 2 })
println(numbers.sumOf { it.toDouble() / 2 })
fold 与 reduce
函数 reduce() 和 fold() ,它们依次将所提供的操作应用于集合元素并返回累积的结果。 操作有两个参数:先前的累积值和集合元素。 区别在于:fold() 接受一个初始值并将其用作第一步的累积值,而 reduce() 的第一步则将第一个和第二个元素作为第一步的操作参数。 示例代码:
val numbers = listOf(5, 2, 10, 4)
val simpleSum = numbers.reduce { sum, element -> sum + element }
println(simpleSum)
val sumDoubled = numbers.reduce { sum, element -> sum + element * 2 }
println(sumDoubled)
val sumDoubled1 = numbers.fold(0) { sum, element -> sum + element * 2 }
println(sumDoubled1)
反向操作使用函数 reduceRight() 和 foldRight() ,从最后一个元素开始,然后再继续到前一个元素。 操作参数会更改其顺序:第一个参数变为元素,然后第二个参数变为累积值。
val numbers = listOf(5, 2, 10, 4)
val sumDoubledRight = numbers.foldRight(0) { element, sum -> sum + element * 2 }
println(sumDoubledRight)
带上元素索引使用 reduceIndexed() 与 foldIndexed() ,同理有反向函数——reduceRightIndexed() 与foldRightIndexed() 。 还有一些对null安全的处理函数 reduceOrNull() reduceRightOrNull() reduceIndexedOrNull() reduceRightIndexedOrNull() 如需保存中间累加值的使用 runningFold() (或者相同方法 scan() ) 与 runningReduce() . 示例代码:
val numbers = listOf(0, 1, 2, 3, 4, 5)
val runningReduceSum = numbers.runningReduce { sum, item -> sum + item }
val runningFoldSum = numbers.runningFold(10) { sum, item -> sum + item }
val transform = { index: Int, element: Int -> "N = ${index + 1}: $element" }
println(runningReduceSum.mapIndexed(transform).joinToString("\n", "Sum of first N elements with runningReduce:\n"))
println(runningFoldSum.mapIndexed(transform).joinToString("\n", "Sum of first N elements with runningFold:\n"))
执行结果:
Sum of first N elements with runningFold:
N = 1: 10
N = 2: 10
N = 3: 11
N = 4: 13
N = 5: 16
N = 6: 20
N = 7: 25
写操作
支持MutableCollection 类型的数据结构,如List、Set。
还可以使用 plus 运算符 - plusAssign (+=) 添加元素。
添加元素
使用add() 、addAll() 函数
val numbers = mutableListOf(1, 2, 3, 4)
numbers.add(5)
numbers.addAll(arrayOf(7, 8))
println(numbers)
numbers.addAll(2, setOf(3, 4))
println(numbers)
使用plus运算符
val numbers = mutableListOf("one", "two")
numbers += "three"
println(numbers)
numbers += listOf("four", "five")
println(numbers)
删除操作
使用remove() 、clear() 、retainAll() 、removeAll() 等函数。 retainAll() :与 removeAll() 相反:它移除除参数集合中的元素之外的所有元素, 可以添加过滤条件。 示例代码:
val numbers = mutableListOf(1, 2, 3, 4, 3)
numbers.remove(3)
println(numbers)
numbers.remove(5)
println(numbers)
numbers.retainAll { it >= 3 }
println(numbers)
numbers.clear()
println(numbers)
val numbersSet = mutableSetOf("one", "two", "three", "four")
numbersSet.removeAll(setOf("one", "two"))
println(numbersSet)
使用 minusAssign (-=) ——原地修改版的 minus 操作符
val numbers = mutableListOf("one", "two", "three", "three", "four")
numbers -= "three"
println(numbers)
numbers -= listOf("four", "five")
println(numbers)
更新操作
List及Map分别提供,Set更新无意义
List专有操作
List操作包括按索引取元素、取列表的一部分、查找元素位置(线性查找、有序列表二分查找、Comparator 二分搜索、比较函数二分搜索) 、写操作(添加、更新、删除、排序)
按索引取元素
elementAt() 集合方法根据索引获取元素 first() 获取第一个元素 last() 获取最后一个元素 get() 或者[index] List方法 List 长度小于指定的索引,则抛出异常。 另外,还有两个函数能避免此类异常: getOrElse() 提供用于计算默认值的函数,如果集合中不存在索引,则返回默认值。 getOrNull() 返回 null 作为默认值 示例代码
val numbers = listOf(1, 2, 3, 4)
println(numbers.get(0))
println(numbers[0])
println(numbers.getOrNull(5))
println(numbers.getOrElse(5, {it}))
取列表一部分
集合的取列表部分的操作仍然适用,List还提供了subList 方法。该方法是引用操作,并不是副本操作。原始列表或者子列表变更都会引起另一个的变更。
val numbers = (0..13).toList()
println(numbers.subList(3, 6))
查找之线性查找
使用 indexOf() 或 lastIndexOf() 函数找到元素的位置 调用成功则返回位置索引,不成功返回-1
还有如下方法: indexOfFirst() 返回与谓词匹配的第一个元素的索引,如果没有此类元素,则返回 -1。 indexOfLast() 返回与谓词匹配的最后一个元素的索引,如果没有此类元素,则返回 -1。 示例代码:
val numbers = mutableListOf(1, 2, 3, 4)
println(numbers.indexOfFirst { it > 2})
println(numbers.indexOfLast { it % 2 == 1})
查找之二分查找
二分查找需要列表有序,效率较高 调用函数 binarySearch() ,成功返回索引,失败返回-insertionPoint - 1 ,其中 insertionPoint 为应插入此元素的索引 示例代码:
val numbers = mutableListOf("one", "two", "three", "four")
numbers.sort()
println(numbers)
println(numbers.binarySearch("two"))
println(numbers.binarySearch("z"))
println(numbers.binarySearch("two", 0, 2))
执行结果:
[four, one, three, two]
3
-5
-3
查找之Comparator二分搜索
如果列表元素不是 Comparable,则应提供一个用于二分搜索的 Comparator。 该列表必须根据此 Comparator 以升序排序。 示例代码:
data class Product(val name: String, val price: Double)
fun main() {
val productList = listOf(
Product("WebStorm", 49.0),
Product("AppCode", 99.0),
Product("DotTrace", 129.0),
Product("ReSharper", 149.0))
println(productList.binarySearch(Product("AppCode", 99.0), compareBy<Product> { it.price }.thenBy { it.name }))
}
按照价格升序排列,然后使用二分法搜索。
按照字母排序,不区分大小写
val colors = listOf("Blue", "green", "ORANGE", "Red", "yellow")
println(colors.binarySearch("RED", String.CASE_INSENSITIVE_ORDER))
查找之比较函数二分搜索
比较函数将元素映射到 Int 值,并搜索函数返回 0 的元素。 该列表必须根据提供的函数以升序排序;换句话说, 比较的返回值必须从一个列表元素增长到下一个列表元素。
import kotlin.math.sign
data class Product(val name: String, val price: Double)
fun priceComparison(product: Product, price: Double) = sign(product.price - price).toInt()
fun main() {
val productList = listOf(
Product("WebStorm", 49.0),
Product("AppCode", 99.0),
Product("DotTrace", 129.0),
Product("ReSharper", 149.0))
println(productList.binarySearch { priceComparison(it, 99.0) })
}
写操作之添加
除了集合写操作中描述的集合修改操作之外, 可变列表还支持特定的写操作。 使用 add() 或 addAll() 并提供元素插入的位置作为附加参数。 位置之后的所有元素都将向右移动
val numbers = mutableListOf("one", "five", "six")
numbers.add(1, "two")
numbers.addAll(2, listOf("three", "four"))
println(numbers)
写操作之更新
set() 及其操作符形式 [] 。set() 不会更改其他元素的索引。 示例代码:
val numbers = mutableListOf("one", "five", "three")
numbers[1] = "two"
println(numbers)
fill() 简单地将所有集合元素的值替换为指定值
val numbers = mutableListOf(1, 2, 3, 4)
numbers.fill(3)
写操作之删除
使用 removeAt() 函数,删除元素之后的所有元素索引都减1
val numbers = mutableListOf(1, 2, 3, 4, 3)
numbers.removeAt(1)
写操作之排序
集合排序方法与列表排序方法稍有差异 sort* 在所有排序函数的名称中代替 sorted* :sort() 、sortDescending() 、sortBy() 等等。 shuffle() 代替 shuffled()。 reverse() 代替 reversed()。 asReversed() 在可变列表上调用会返回另一个可变列表,该列表是原始列表的反向视图。 示例代码
val numbers = mutableListOf("one", "two", "three", "four")
numbers.sort()
println("Sort into ascending: $numbers")
numbers.sortDescending()
println("Sort into descending: $numbers")
numbers.sortBy { it.length }
println("Sort into ascending by length: $numbers")
numbers.sortByDescending { it.last() }
println("Sort into descending by the last letter: $numbers")
numbers.sortWith(compareBy<String> { it.length }.thenBy { it })
println("Sort by Comparator: $numbers")
numbers.shuffle()
println("Shuffle: $numbers")
numbers.reverse()
println("Reverse: $numbers")
Set专有操作
常用操作:找出集合间的交集、并集或差集。 并集: union() 或者a union b 交集:intersect() 或者a intersect b 差集: subtract() 或者a subtract b 示例:
val numbers = setOf("one", "two", "three")
println(numbers union setOf("four", "five"))
println(setOf("four", "five") union numbers)
println(numbers intersect setOf("two", "one"))
println(numbers subtract setOf("three", "four"))
println(numbers subtract setOf("four", "three"))
上述操作同样适用于List
val list1 = listOf(1, 1, 2 ,3, 5, 8, -1)
val list2 = listOf(1, 1, 2, 2 ,3, 5)
println(list1 intersect list2)
println(list1 union list2)
Map专有操作
Map操作分为读操作和写操作,读操作包括获取键与值、过滤、加减操作符。写操作包括添加更新条目、删除条目
Map读操作
取键和值
根据键获取值:get() 函数或者[key] 根据值获取键: getValue() getOrElse() 对于不存在的键,其值由给定的 lambda 表达式返回 getOrDefault() 如果找不到键,则返回指定的默认值.
val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
println(numbersMap.get("one"))
println(numbersMap["one"])
println(numbersMap.getOrDefault("four", 10))
println(numbersMap["five"])
println(numbersMap.keys)
println(numbersMap.values)
过滤
使用filter 函数 按照键过滤使用filterKeys() 按照值过滤使用filterValues()
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
val filteredMap = numbersMap.filter { (key, value) -> key.endsWith("1") && value > 10}
val filteredKeysMap = numbersMap.filterKeys { it.endsWith("1") }
val filteredValuesMap = numbersMap.filterValues { it < 10 }
println(filteredKeysMap)
println(filteredValuesMap)
加减操作符
使用plus (+)与 minus (-)
val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
println(numbersMap + Pair("four", 4))
println(numbersMap + Pair("one", 10))
println(numbersMap + mapOf("five" to 5, "one" to 11))
println(numbersMap - "one")
println(numbersMap - listOf("two", "four"))
Map写操作
写操作针对Mutable类型的Map,遵循下列原则:
- 值可以更新。 反过来,键也永远不会改变:添加条目后,键是不变的。
- 每个键都有一个与之关联的值。也可以添加和删除整个条目。
添加与更新条目
添加单个条目使用put() , 添加多个使用putAll() 。
在 Map 类中,新元素的位置由其键顺序定义。
如果给定键已存在于 Map 中,则 put() 与 putAll() 都将覆盖值。 因此,可以使用它们来更新 Map 条目的值。
val numbersMap = mutableMapOf("one" to 1, "two" to 2)
numbersMap.put("three", 3)
val previousValue = numbersMap.put("one", 11)
numbersMap.putAll(setOf("four" to 4, "five" to 5))
numbersMap["three"] = 3
numbersMap += mapOf("four" to 4, "five" to 5)
println(numbersMap)
删除条目
使用remove() 函数,可以传递键或整个键值对,传入键值对时候需要键和值都匹配才能删除。
val numbersMap = mutableMapOf("one" to 1, "two" to 2, "three" to 3)
numbersMap.remove("one")
println(numbersMap)
numbersMap.remove("three", 4)
println(numbersMap)
numbersMap.keys.remove("one")
println(numbersMap)
numbersMap.values.remove(3)
println(numbersMap)
numbersMap -= "two"
println(numbersMap)
numbersMap -= "five"
println(numbersMap)
官方文档之集合
|