「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!」
作者:Elye
前言
你们知道 Kotlin Collection 的操作函数有多少个?200多个。按照函数名的字母顺序浏览一遍可能都得花点时间,更别提快速找到满足自己业务场景的函数了,甚至有些函数你可能都不知道它的存在,此情此景甚是苦恼啊!好在最近阅读一遍关于 Kotlin 集合操作函数的文章,作者根据函数的功能性,将其分为 5 类:Creation
、Convert
、Change
、Choose
和 Conclude
,针对每个大类作者进一步划分子类,所有类型名称皆以 C 开头以呼应 Collection 集合,情怀如斯啊!通过分类形成的快查备忘录让所有函数以树形结构呈现在各位面前,查找起来更方便。贴心的作者对于一些不太容易理解的函数,还在文章中提供一些插图辅助说明,对于一些常见的函数,作者也添加了官方文档的链接以便我们深入了解。感谢作者的整理,下面开始正文。
分类
主要分为 5 种类别:
-
Creation:新建集合,例如
listOf
-
Convert:转换集合,例如
asMap
-
Change:改变集合,例如
map
-
Choose:访问集合,例如
get
-
Conclude:汇总集合,例如
sum
如何快速查找
场景一:
假设你想寻找一个可以将列表中的所有整数项值相乘的函数,考虑到最后的结果是由集合内所有元素相乘得到,所以你应该去 Conclude
类别下查找,浏览该类别下的所有函数后,你将如愿找到 reduce
函数
list.reduce{ result, item -> result * item }
复制代码
场景二:
假设你想找一个可以将列表拆分成几个固定大小的子列表的函数,考虑到最终结果是将现有列表转换为另一种形式的集合。所以你应该去 Change
类别中去查找。查阅该类别下的所有函数后,你会如愿找到 chunk
函数
list.chunked(3)
复制代码
类别之间的关系
上面 5 种类别,我们可以用状态机的概念将其联系起来,因为 Creation
类别是用于创建集合的,所以它是初始状态,Change
和 Convert
是可以相互转换的中间状态,而最终状态为 Conclude
或 Choose
。 例如:
listOf(1, 2, 3) // Creation
.map { it * 2 } // Change
.sum() // Conclude
复制代码
也可以直接从初始状态到最终状态,例如:
listOf(1, 2, 3) // Creation
.sum() // Conclude
复制代码
Creation
我们可以对 Creation
类别进行进一步的细分,以便我们更快的查找函数。
- Creation Compose — 实例化新集合
- Creation Copy — 复制集合
- Creation Catch — 类似 try-catch 的方式创建集合
Creation Compose — 实例化新集合
// 空集合
// 只读集合
// 可变集合
mutableListOf, mutableMapOf, mutableSetOf, arrayListOf
// 混合源构建集合
// 链表集合
linkedMapOf, linkedSetOf (more in stackOverflow)
// 有序集合
sortedMapOf, sortedSetOf (more in stackOverflow)
// 哈希集合
hashMapOf, hashSetOf (more in stackOverflow)
// 利用代码逻辑创建集合
Creation Copy — 复制集合
copyInto // 将数组或其子范围复制到目标数组中并返回目标数组
copyOfRange // 部分复制
copyOf // 完全复制
toCollection // 复制到集合
Creation Catch — 类似 try-catch 的方式创建集合
ifEmpty // 若为空则赋予默认值
orEmpty // 若为 null 则赋予空值
requireNoNulls // 若某个元素为 null 则程序崩溃
listOfNotNull // 利用传入参数中所有非 null 元素组成列表
Conversion
Conversion 类别下的函数主要用于将集合的类型更改为另一种类型。
我们可以对 Conversion
类别进行进一步的细分,以便我们更快的查找函数。
- Conversion Copy — 转换为另一种类型的新集合
- Conversion Cite — 转换为另一种类型的原集合引用
一个很好的例子就是 toIntArray
(Copy) 和 asIntArray
(Cite):
// toIntArray example (a new copy)
val uIntArray = UIntArray(3) { 1U }
val toIntArray = uIntArray.toIntArray()toIntArray[1] = 2
println(toIntArray.toList()) // [1, 2, 1]
println(uIntArray.toList()) // [1, 1, 1]// asIntArray example (a reference copy)
val uIntArray = UIntArray(3) { 1U }
val asIntArray = uIntArray.asIntArray()
asIntArray[1] = 2
println(asIntArray.toList()) // [1, 2, 1]
println(uIntArray.toList()) // [1, 2, 1]
复制代码
Conversion Copy — 转换为另一种类型的新集合
// 转换为数组类型
toBooleanArray, toByteArray, toCharArray, toDoubleArray, toFloatArray, toIntArray, toLongArray, toShortArray, toTypedArray, toUByteArray, toUIntArray, toULongArray, toUShortArray
// 转换为只读集合
// 转换为可变集合
toMutableList, toMutableMap, toMutableSet, toHashSet
// 转换为有序集合
// 转 Entries 为 Pair
toPair
可以将 map 的 entry
转换为 Pair
。示例代码如下:
map.entries.map { it.toPair() }
// This is essentially
map.toList()
// Underlying `toList` of Map, it is using `toPair()`
// to do all the conversion of entries to Pair
复制代码
// 转 Map 为 Properties
toProperties
可以将 Map
转换成 Properties(Java原生类),它是Map<String, String>
的子类。
val map = mapOf("x" to "value A", "y" to "value B")
val props = map.toProperties()
println(props.getProperty("x")) // value A
println(props.getProperty("z")) // null
println(props.getProperty("y", "fail")) // value B
println(props.getProperty("z", "fail")) // fail
println(map.get("x")) // value A
println(map.get("z")) // null
println(map.getOrDefault("y", "fail")) // value B
println(map.getOrDefault("z", "fail")) // fail
复制代码
Conversion Cite — 转换为另一种类型的原集合引用
// 作为数组类型
asByteArray, asIntArray, asLongArray, asShortArray, asUByteArray, asUIntArray, asULongArray, asUShortArray,
// 作为集合类型. 关于 list 和 sequestion, 请转阅 此文
asIterable, asList, asSequence
// 转为带索引的迭代器
withIndex
可以将 List 转换为 IndexedValue iterable (带索引的 iterable )
val list = listOf("A", "B", "C")
val indexed = list.withIndex()
println(list) // [A, B, C]
println(indexed.toList())
// [IndexedValue(index=0, value=A),
// IndexedValue(index=1, value=B),
// IndexedValue(index=2, value=C)]
复制代码
// 转为带自定义默认值的 Map
withDefault
可以将 Map 转换成带自定义默认值的 Map
val map = mutableMapOf(1 to 1)
// customize default value return x 2 of key
val default = map.withDefault { k -> k * 2 }
println(default.getValue(10)) // return 20
println(map.getValue(10)) // crash as no key 10
复制代码
Change
Change 类别下的函数主要用于改变集合内容或者集合的结构。对其进行进一步的细分:
-
Change Content (改变内容):改变集合类型和元素类型,只改变集合的内容。例如
filter
函数。 -
Change Contour (改变结构):改变集合类型(例如,List 执行
groupBy
函数会输出 Map 类型)或更改元素类型(例如,chunked
函数会把元素类型从 Int 转变为 List<Int>)
Change-Content — 只改内容不改结构
改变内容有两种情况:
- 创建一个新的集合且改变内容并返回
- 改变原集合且不返回任何内容
看一个简单的示例,add
和 plus
val list = listOf(1)
val mutableList = mutableListOf(1)
println(list) // [1]
println(mutableList) // [1]
val newList = list.plus(2)
mutableList.add(2)
println(list) // [1]
println(newList) // [1, 2]
println(mutableList) // [1, 2]
复制代码
两个函数的目的是一致的,但是结果如上图所示,有所不同。为了区分两者,我们用斜体表示改变原集合这一类函数,如***add
***,用正常字体表示另外一类函数,如 plus
。
看看函数列表(注意区分斜体)
// 改变内容
set, setValue //(more info in stackoverflow)
// 添加内容
plus, plusElement, //(more info in stackoverflow)
plusAssign, //(more info in stackoverflow)
add, addAll, put, putAll
// 移除内容
minus, minusElement, //(more info in stackoverflow)
minusAssign, //(more info in stackoverflow)
remove
// 从集合的头部或者尾部移除
drop, dropLast, dropLastWhile, dropWhile,removeFirst, removeFirstOrNull, removeLast, removeLastOrNull,
// 从集合的头部或者尾部选取
take, takeLastWhile, takeLast, takeWhile,
// 从集合中选取
// 仅获取不同(唯一)值
// 给定两个集合执行维恩图操作
union, intersect, retainAll, subtract, removeAll
// 将元素转成另外一个值
map, mapTo,mapIndexed, mapIndexedTo,mapKeys, mapKeysTo, mapValues, mapValuesTo, replaceAll, fill
// 将非 null 元素转成另外一个值以保证结果集内无 null 值
mapNotNull, mapNotNullTo, mapIndexedNotNull, mapIndexedNotNullTo
注意:
map
函数可以将 List 转换为另一种结构或者另一种元素类型,这些我们会在后面的 Change Contour 类别中提及。
// 过滤部分内容
filter, filterIndexed, filterIndexedTo, filterIsInstance, filterIsInstanceTo, filterKeys, filterNot, filterNotNull, filterNotNullTo, filterNotTo, filterTo, filterValues
// 反转内容 (查阅此文以辨别这几个函数的区别)
reversed,reversedArray, reverse, asReversed
// 排序
sorted, sortedArray, sortedArrayDescending, sortedArrayWith, sortedBy, sortedByDescending, sortedDescending, sortedWith sort, sortBy, sortByDescending, sortDescending, sortWith
// 打乱内容
// 和 fold 或者 reduce类似, 但是执行过程是每个元素逐个完成的
scan, scanIndexed, scanReduce, scanReduceIndexed
Change Contour — 既改内容又改结构
此类函数的结果要么会改变集合类型,例如 List 到 Map ,要么会改变元素的类型,例如List<String> 到 List<Map>。
// 分组聚合 形成 Map
aggregate, aggregateTo // (必备条件: groupingBy)
// Example
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
val aggregated = numbers.groupingBy { it % 3 }
.aggregate { key, accumulator: Int?, element, first ->
if (first) element else accumulator?.plus(element)
}
println(aggregated) // {1=12, 2=15, 0=18}
复制代码
// 分组计数 形成 Map
eachCount, eachCountTo //(必备条件:groupingBy)
// Example Code
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
val eachCount = numbers.groupingBy { it % 2 }.eachCount()
println(eachCount) // {1=5, 0=4}
复制代码
// 使用 Map key 链接每个元素
associate, associateBy, associateByTo, associateTo, associateWith, associateWithTo //(查阅 此文 以了解它们的区别)
// Example code
val list = listOf(1, 2, 3, 4, 5)
val associate = list.associateWith { it * it }
println(associate) // {1=1, 2=4, 3=9, 4=16, 5=25}
复制代码
// 按规则将集合分组形成 value 类型为 List 的 Map
// Example code
val list = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
val groupBy = list.groupBy{it % 3}
println(groupBy)
复制代码
// 展平成一个列表
// Example code
val map = mapOf(1 to listOf(1, 2), 2 to listOf(2, 4))
val flatMap = map.flatMap { it.value }
println(flatMap) // [1, 2, 2, 4]
// Example code
val list = listOf(listOf(1, 2), listOf(2, 4))
val flatten = list.flatten()
println(flatten) // [1, 2, 2, 4]
复制代码
// 将元素转为另一种类型
map, mapTo, mapIndexed, mapIndexedTo, mapKeys, mapKeysTo, mapValues, mapValuesTo
// 将非 null 元素转为另一种类型以保证结果集内无 null 值
mapNotNull, mapNotNullTo, mapIndexedNotNull, mapIndexedNotNullTo
// Example code
val days = listOf("Monday", "Tuesday", "Wednesday", "Thursday")
val daysLength = days.map { it.length }
println(daysLength)
复制代码
// 将元素分类到不同的列表中
// Example code
val list = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
val chunked = list.chunked(4)
val windowed = list.windowed(4, 3, true)
val partition = list.partition { it % 2 == 0 }
println(chunked) // [[1, 2, 3, 4], [5, 6, 7, 8], [9]]
println(windowed) // [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8, 9]]
println(partition)// ([2, 4, 6, 8], [1, 3, 5, 7, 9])
复制代码
// 将两个元素联合在一起或者解除联合
// Example code
val list = listOf(1, 2, 3, 4, 5)
val list2 = listOf(6, 7, 8, 9)
val zip = list.zip(list2)
println(zip)
// Example code
val list = listOf(1, 2, 3, 4)
val zipWithNext = list.zipWithNext()
println(zipWithNext)
// Example code
val list = listOf(1 to 2, 3 to 4, 5 to 6)
val unzip = list.unzip()
println(unzip)
复制代码
Choose
Choose 类别下的函数主要用于访问集合中的特定元素,将其进一步细分:
- Choose Certain — 根据固定位置访问集合元素
- Choose Clue — 根据给定条件访问集合元素
无论如何,结果都是集合中的元素之一。
Choose Certain — 根据固定位置访问集合元素
若你觉得下面这些函数看起来很相似,则下文链接将有助于你区分它们之间的差异
levelup.gitconnected.com/kotlin-has-…
// 主要用于 List 和 Map
get, getOrDefault, getOrElse, getOrNull, getOrPut,getValue // (more info in stackoverflow and check withDefault above)
// 主要用于 Sequence 和 Set
elementAt, elementAtOrElse, elementAtOrNull
// 用于解构
component1, component2, component3, component4, component5
// 随机获取
// 手动迭代
// 获取集合中的唯一元素
Choose Clue — 根据给定条件访问集合元素
// 从第一个元素开始查找
// 从倒数第一个元素开始查找
// 查找所寻元素的索引
indexOf, lastIndexOf, indexOfFirst, indexOfLast
// 在有序集合内查找
Conclude
Conclude 类别下的函数主要是按照一定的规则利用集合中的元素生成一个结果,将其进一步细化:
- Conclude Choice — 判断,例如
isEmpty
。 - Conclude Compute — 计算,例如
average
。 - Conclude Combine — 合并,例如 string, hash code。
- Conclude Carryover — 遍历,例如
forEach
。
Conclude Choice — 判断
// 存在性检查
contains, containsAll, containsKey, containsValue
isEmpty, isNotEmpty, isNullOrEmpty (查阅 此文)
// 比较
contentEquals, contentDeepEquals
Conclude Compute — 计算
// 统计相关
average, count, max, maxBy, maxWith, min, minBy, minWith
sum, sumBy, sumByDouble (double float type)
// 演绎计算 (类似于 scan)
fold, foldIndexed, foldRight, foldRightIndexed, foldTo,
reduce, reduceIndexed, reduceOrNull, reduceRight,
reduceRightIndexed, reduceRightOrNull, reduceTo
Conclude Combine — 合并
// 生成 Hash Code
contentHashCode, contentDeepHashCode
// 生成字符串
contentToString, contentDeepToString, joinTo, joinToString, subarrayContentToString
Conclude Carrayover — 遍历
// 尾部循环
// 中段循环返回集合本身 (如 side effect function)
备忘录
综上所述,整理出所有功能的备忘录备查,可以打印出来贴在墙上 ?
结语
按照作者的分类,我感觉树形结构可能更适合查找,于是整理了一份思维导图。