在上一篇文章Kotlin——高级篇(四):集合(Array、List、Set、Map)基础中讲解到了数组Array<T>
、集合(List
、Set
、Map
)的定义与初始化。可是因为篇幅的缘由,未讲解到操做他们的经常使用高阶函数。故而今天这篇文章详细的讲解这些函数。对他们的做用进行剖。并实例讲解他们的应用场景。当看完这篇文章,我相信你能对集合使用的驾轻就熟。html
在上一篇文章中讲解数组(Array<T>
)的与集合的时候也提到了关于集合转换的高阶函数。下面用源码的角度去分析并用实例去讲解其转换的过程。java
当咱们声明一个集合,能够把这个集合根据调用集合类相应的高阶函数来转换成相应的数组。集合类提供了
toIntArray()
、toDoubleArray()
、toFloatArray()
、toBetArray()
等高阶函数去处理。下面提供一个函数的源码,其余函数的源码处理逻辑是相同的,有兴趣的朋友能够去看看这个源码类。git
源码:github
public fun Collection<Int>.toIntArray(): IntArray {
val result = IntArray(size)
var index = 0
for (element in this)
result[index++] = element
return result
}
复制代码
解释:从上面的源码,咱们能够看出,该函数的返回类型时IntArray
类型,即表示一个Int
类型的数组。该函数的逻辑是定义一个Int
类型的数组,而后遍历集合,把集合的元素一个一个的添加到定义的数组当中。数组
实例:函数
fun listToArray(){
val list = listOf<Int>(1,2,3,4,5,6) // 声明一个Int类型的List
val listArray = list.toIntArray() // 转换
println(list.javaClass.toString()) // 打印list的类型
println(listArray.javaClass.toString()) // 打印listArray的类型
println(listArray[1])
}
复制代码
输出结果:post
变量list的类型为:class java.util.LinkedHashSet
变量listArray的类型为:class [I
2
复制代码
咱们知道在
Kotlin
中,集合可分为不可变集合与可变集合。咱们声明一个集合或者数组,能够转换成相应类型的集合。调用toXXX()
转换成不可变集合。调用toMutableXXX()
转换为可变集合。集合类提供了toList()
、toMutableList()
、toSet()
、toMutableSet()
、toHashSet()
、toMap()
等高阶函数去处理。同理也是从源码的角度去分析。学习
源码:这个是集合转集合的源码。数组转集合的源码还要简单些。this
public fun <T> Iterable<T>.toList(): List<T> {
if (this is Collection) {
return when (size) {
0 -> emptyList()
1 -> listOf(if (this is List) get(0) else iterator().next())
else -> this.toMutableList()
}
}
return this.toMutableList().optimizeReadOnlyList()
}
复制代码
解释:首先判断是否是一个集合,若是是一个集合的状况,则根据集合的元素个数来执行相应的逻辑,当元素的个数为0
时,返回一个空集合。当为1
个的时候,用listOf()
去初始化一个List
集合。在这个新集合中去这个判断原集合的类型是否是返回集合的类型,若是是,则获取原集合的第一个元素做为新集合的元素返回。反之,则遍历原集合的元素。当原集合个数不为0
或1
时,使用toMutableList()
转换成list。若是不是集合,则直接使用toMutableList()
转换。这里的optimizeReadOnlyList()
函数的逻辑便是上面原集合的逻辑。spa
解释起来很复杂,仍是用代码说话吧...
实例:
// 数组转集合
fun arrayToList() {
val arr = arrayOf(1,3,5,7,9)
val list = arr.toList()
println("变量arr的类型为:${arr.javaClass}")
println("变量list的类型为:${list.javaClass}")
println(list[1])
}
// 集合转集合,这里用Set转List
fun listToList(){
val set = setOf(1)
val setTolist = set.toList()
println("变量set的类型为:${set.javaClass}")
println("变量setTolist的类型为:${setTolist.javaClass}")
println(setTolist[0])
}
复制代码
输出结果为:
变量arr的类型为:class [Ljava.lang.Integer;
变量list的类型为:class java.util.ArrayList
3
变量set的类型为:class java.util.Collections$SingletonSet
变量setTolist的类型为:class java.util.Collections$SingletonList
1
复制代码
关于集合转换的问题就讲到这里,有兴趣的同窗能够去看看源码的实现。
关于集合操做类的函数大体分为六类,他们几乎上囊括了源码中实现的操做方法。下面对这6
类操做符进行一一的讲解,不过这里就不对他们的源码进行分析了。你们有兴趣的话能够去看看他们的源码实现。几乎上都存在于_Collections.kt
这个文件中
元素操做符在这里包括:
contains(元素)
: 检查集合中是否包含指定的元素,若存在则返回true
,反之返回false
elementAt(index)
: 获取对应下标的元素。若下标越界,会抛出IndexOutOfBoundsException(下标越界)
异常,同get(index)
同样elementAtOrElse(index,{...})
: 获取对应下标的元素。若下标越界,返回默认值,此默认值就是你传入的下标的运算值elementAtOrNull(index)
: 获取对应下标的元素。若下标越界,返回null
first()
: 获取第一个元素,若集合为空集合,这会抛出NoSuchElementException
异常first{}
: 获取指定元素的第一个元素。若不知足条件,则抛出NoSuchElementException
异常firstOrNull()
: 获取第一个元素,若集合为空集合,返回null
firstOrNull{}
: 获取指定元素的第一个元素。若不知足条件,返回null
getOrElse(index,{...})
: 同elementAtOrElse
同样getOrNull(index)
: 同elementAtOrNull
同样last()
: 同first()
相反last{}
: 同first{}
相反lastOrNull{}
: 同firstOrNull()
相反lastOrNull()
: 同firstOrNull{}
相反indexOf(元素)
: 返回指定元素的下标,若不存在,则返回-1
indexOfFirst{...}
: 返回第一个知足条件元素的下标,若不存在,则返回-1
indexOfLast{...}
: 返回最后一个知足条件元素的下标,若不存在,则返回-1
single()
: 若集合的长度等于0
,则抛出NoSuchElementException
异常,若等于1
,则返回第一个元素。反之,则抛出IllegalArgumentException
异常single{}
: 找到集合中知足条件的元素,若元素知足条件,则返回该元素。不然会根据不一样的条件,抛出异常。这个方法慎用singleOrNull()
: 若集合的长度等于1
,则返回第一个元素。不然,返回null
singleOrNull{}
: 找到集合中知足条件的元素,若元素知足条件,则返回该元素。不然返回null
forEach{...}
: 遍历元素。通常用做元素的打印forEachIndexed{index,value}
: 遍历元素,可得到集合中元素的下标。通常用做元素以及下标的打印componentX()
: 这个函数在前面的章节中提过屡次了。用于获取元素。其中的X
只能表明1..5
。详情可看下面的例子
例:
val list = listOf("kotlin","Android","Java","PHP","Python","IOS")
println(" ------ contains -------")
println(list.contains("JS"))
println(" ------ elementAt -------")
println(list.elementAt(2))
println(list.elementAtOrElse(10,{it}))
println(list.elementAtOrNull(10))
println(" ------ get -------")
println(list.get(2))
println(list.getOrElse(10,{it}))
println(list.getOrNull(10))
println(" ------ first -------")
println(list.first())
println(list.first{ it == "Android" })
println(list.firstOrNull())
println(list.firstOrNull { it == "Android" })
println(" ------ last -------")
println(list.last())
println(list.last{ it == "Android" })
println(list.lastOrNull())
println(list.lastOrNull { it == "Android" })
println(" ------ indexOf -------")
println(list.indexOf("Android"))
println(list.indexOfFirst { it == "Android" })
println(list.indexOfLast { it == "Android" })
println(" ------ single -------")
val list2 = listOf("list")
println(list2.single()) // 只有当集合只有一个元素时,才去用这个函数,否则都会抛出异常。
println(list2.single { it == "list" }) //当集合中的元素知足条件时,才去用这个函数,否则都会抛出异常。若知足条件返回该元素
println(list2.singleOrNull()) // 只有当集合只有一个元素时,才去用这个函数,否则都会返回null。
println(list2.singleOrNull { it == "list" }) //当集合中的元素知足条件时,才去用这个函数,否则返回null。若知足条件返回该元素
println(" ------ forEach -------")
list.forEach { println(it) }
list.forEachIndexed { index, it -> println("index : $index \t value = $it") }
println(" ------ componentX -------")
println(list.component1()) // 等价于`list[0] <=> list.get(0)`
println(list.component2()) // 等价于`list[1] <=> list.get(1)`
println(list.component3()) // 等价于`list[2] <=> list.get(2)`
println(list.component4()) // 等价于`list[3] <=> list.get(3)`
println(list.component5()) // 等价于`list[4] <=> list.get(4)`
复制代码
输出结果为:
------ contains -------
false
------ elementAt -------
Java
10
null
------ get -------
Java
10
null
------ first -------
kotlin
Android
kotlin
Android
------ last -------
IOS
Android
IOS
Android
------ indexOf -------
1
1
1
------ single -------
list
list
list
list
------ forEach -------
kotlin
Android
Java
PHP
Python
IOS
index : 0 value = kotlin
index : 1 value = Android
index : 2 value = Java
index : 3 value = PHP
index : 4 value = Python
index : 5 value = IOS
------ componentX -------
kotlin
Android
Java
PHP
Python
复制代码
顺序操做符包括:
reversed()
: 反序。即和初始化的顺序反过来。sorted()
: 天然升序。sortedBy{}
: 根据条件升序,即把不知足条件的放在前面,知足条件的放在后面sortedDescending()
: 天然降序。sortedByDescending{}
: 根据条件降序。和sortedBy{}
相反
其中从源码的角度说:
sorted()
函数的核心是sort()
函数。但这个sort()
函数我不能直接调用罢了。reversed()
函数调用的是Java
中的reversed()
函数。3
个函数实现的核心为sortWith()
函数。故而咱们也能够用sortWith()
来实现其余的排序方式例:
val list1 = listOf(-1,-3,1,3,5,6,7,2,4,10,9,8)
// 反序
println(list1.reversed())
// 升序
println(list1.sorted())
// 根据条件升序,即把不知足条件的放在前面,知足条件的放在后面
println(list1.sortedBy { it % 2 == 0})
// 降序
println(list1.sortedDescending())
// 根据条件降序,和`sortedBy{}`相反
println(list1.sortedByDescending { it % 2 == 0 })
复制代码
输出结果为:
[8, 9, 10, 4, 2, 7, 6, 5, 3, 1, -3, -1]
[-3, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[-1, -3, 1, 3, 5, 7, 9, 6, 2, 4, 10, 8]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -3]
[6, 2, 4, 10, 8, -1, -3, 1, 3, 5, 7, 9]
复制代码
映射操做符包括:
map{...}
: 把每一个元素按照特定的方法进行转换,组成一个新的集合。mapNotNull{...}
: 同map{}
函数的做用相同,只是过滤掉转换以后为null
的元素mapIndexed{index,result}
: 把每一个元素按照特定的方法进行转换,只是其能够操做元素的下标(index
),组成一个新的集合。mapIndexedNotNull{index,result}
: 同mapIndexed{}
函数的做用相同,只是过滤掉转换以后为null
的元素flatMap{...}
: 根据条件合并两个集合,组成一个新的集合。groupBy{...}
: 分组。即根据条件把集合拆分为为一个Map<K,List<T>>
类型的集合。具体看实例
例:
val list1 = listOf("kotlin","Android","Java","PHP","JavaScript")
println(list1.map { "str-".plus(it) })
println(list1.mapNotNull { "str-".plus(it) })
println(list1.mapIndexed { index, str ->
index.toString().plus("-").plus(str)
})
println(list1.mapIndexedNotNull { index, str ->
index.toString().plus("-").plus(str)
})
println( list1.flatMap { listOf(it,"new-".plus(it)) })
println(list1.groupBy { if (it.startsWith("Java")) "big" else "latter" })
复制代码
输出结果为:
[str-kotlin, str-Android, str-Java, str-PHP, str-JavaScript]
[str-kotlin, str-Android, str-Java, str-PHP, str-JavaScript]
[0-kotlin, 1-Android, 2-Java, 3-PHP, 4-JavaScript]
[0-kotlin, 1-Android, 2-Java, 3-PHP, 4-JavaScript]
[kotlin, new-kotlin, Android, new-Android, Java, new-Java, PHP, new-PHP, JavaScript, new-JavaScript]
{latter=[kotlin, Android, PHP], big=[Java, JavaScript]}
复制代码
过滤操做符包括:
filter{...}
: 把不知足条件的元素过滤掉filterIndexed{...}
: 和filter{}
函数做用相似,只是能够操做集合中元素的下标(index
)filterNot{...}
: 和filter{}
函数的做用相反filterNotNull()
: 过滤掉集合中为null
的元素。take(num)
: 返回集合中前num
个元素组成的集合takeWhile{...}
: 循环遍历集合,从第一个元素开始遍历集合,当第一个出现不知足条件元素的时候,退出遍历。而后把知足条件全部元素组成的集合返回。takeLast(num)
: 返回集合中后num
个元素组成的集合takeLastWhile{...}
: 循环遍历集合,从最后一个元素开始遍历集合,当第一个出现不知足条件元素的时候,退出遍历。而后把知足条件全部元素组成的集合返回。drop(num)
: 过滤集合中前num
个元素dropWhile{...}
: 相同条件下,和执行takeWhile{...}
函数后获得的结果相反dropLast(num)
: 过滤集合中后num
个元素dropLastWhile{...}
: 相同条件下,和执行takeLastWhile{...}
函数后获得的结果相反distinct()
: 去除重复元素distinctBy{...}
: 根据操做元素后的结果去除重复元素slice
: 过滤掉全部不知足执行下标的元素。
例:
val list1 = listOf(-1,-3,1,3,5,6,7,2,4,10,9,8)
val list2 = listOf(1,3,4,5,null,6,null,10)
val list3 = listOf(1,1,5,2,2,6,3,3,7,4,4,8)
println(" ------ filter -------")
println(list1.filter { it > 1 })
println(list1.filterIndexed { index, result ->
index < 5 && result > 3
})
println(list1.filterNot { it > 1 })
println(list2.filterNotNull())
println(" ------ take -------")
println(list1.take(5))
println(list1.takeWhile { it < 5 })
println(list1.takeLast(5))
println(list1.takeLastWhile { it > 5 })
println(" ------ drop -------")
println(list1.drop(5))
println(list1.dropWhile { it < 5 })
println(list1.dropLast(5))
println(list1.dropLastWhile { it > 5 })
println(" ------ distinct -------")
println(list3.distinct())
println(list3.distinctBy { it + 2 })
println(" ------ slice -------")
println(list1.slice(listOf(1,3,5,7)))
println(list1.slice(IntRange(1,5)))
复制代码
输出结果为:
------ filter -------
[3, 5, 6, 7, 2, 4, 10, 9, 8]
[5]
[-1, -3, 1]
[1, 3, 4, 5, 6, 10]
------ take -------
[-1, -3, 1, 3, 5]
[-1, -3, 1, 3]
[2, 4, 10, 9, 8]
[10, 9, 8]
------ drop -------
[6, 7, 2, 4, 10, 9, 8]
[5, 6, 7, 2, 4, 10, 9, 8]
[-1, -3, 1, 3, 5, 6, 7]
[-1, -3, 1, 3, 5, 6, 7, 2, 4]
------ distinct -------
[1, 5, 2, 6, 3, 7, 4, 8]
[1, 5, 2, 6, 3, 7, 4, 8]
------ slice -------
[-3, 3, 6, 2]
[-3, 1, 3, 5, 6]
复制代码
生产操做符包括:
plus()
: 合并两个集合中的元素,组成一个新的集合。也可使用符号+
zip
: 由两个集合按照相同的下标组成一个新集合。该新集合的类型是:List<Pair>
unzip
: 和zip
的做用相反。把一个类型为List<Pair>
的集合拆分为两个集合。看下面的例子partition
: 判断元素是否知足条件把集合拆分为有两个Pair
组成的新集合。
例:
val list1 = listOf(1,2,3,4)
val list2 = listOf("kotlin","Android","Java","PHP","JavaScript")
// plus() 和 `+`同样
println(list1.plus(list2))
println(list1 + list2)
// zip
println(list1.zip(list2))
println(list1.zip(list2){ // 组成的新集合由元素少的原集合决定
it1,it2-> it1.toString().plus("-").plus(it2)
})
// unzip
val newList = listOf(Pair(1,"Kotlin"),Pair(2,"Android"),Pair(3,"Java"),Pair(4,"PHP"))
println(newList.unzip())
// partition
println(list2.partition { it.startsWith("Ja") })
复制代码
输出结果为:
[1, 2, 3, 4, kotlin, Android, Java, PHP, JavaScript]
[1, 2, 3, 4, kotlin, Android, Java, PHP, JavaScript]
[(1, kotlin), (2, Android), (3, Java), (4, PHP)]
[1-kotlin, 2-Android, 3-Java, 4-PHP]
([1, 2, 3, 4], [Kotlin, Android, Java, PHP])
([Java, JavaScript], [kotlin, Android, PHP])
复制代码
统计操做符包括:
any()
: 判断是否是一个集合,如果,则在判断集合是否为空,若为空则返回false
,反之返回true,若不是集合,则返回hasNext
any{...}
: 判断集合中是否存在知足条件的元素。若存在则返回true
,反之返回false
all{...}
: 判断集合中的全部元素是否都知足条件。如果则返回true
,反之则返回false
none()
: 和any()
函数的做用相反none{...}
: 和all{...}
函数的做用相反max()
: 获取集合中最大的元素,若为空元素集合,则返回null
maxBy{...}
: 获取方法处理后返回结果最大值对应那个元素的初始值,若是没有则返回null
min()
: 获取集合中最小的元素,若为空元素集合,则返回null
minBy{...}
: 获取方法处理后返回结果最小值对应那个元素的初始值,若是没有则返回null
sum()
: 计算出集合元素累加的结果。sumBy{...}
: 根据元素运算操做后的结果,而后根据这个结果计算出累加的值。sumByDouble{...}
: 和sumBy{}
类似,不过sumBy{}
是操做Int
类型数据,而sumByDouble{}
操做的是Double
类型数据average()
: 获取平均数reduce{...}
: 从集合中的第一项到最后一项的累计操做。reduceIndexed{...}
: 和reduce{}
做用相同,只是其能够操做元素的下标(index
)reduceRight{...}
: 从集合中的最后一项到第一项的累计操做。reduceRightIndexed{...}
: 和reduceRight{}
做用相同,只是其能够操做元素的下标(index
)fold{...}
: 和reduce{}
相似,可是fold{}
有一个初始值foldIndexed{...}
: 和reduceIndexed{}
相似,可是foldIndexed{}
有一个初始值foldRight{...}
: 和reduceRight{}
相似,可是foldRight{}
有一个初始值foldRightIndexed{...}
: 和reduceRightIndexed{}
相似,可是foldRightIndexed{}
有一个初始值
例:
val list1 = listOf(1,2,3,4,5)
println(" ------ any -------")
println(list1.any())
println(list1.any{it > 10})
println(" ------ all -------")
println(list1.all { it > 2 })
println(" ------ none -------")
println(list1.none())
println(list1.none{ it > 2})
println(" ------ max -------")
println(list1.max())
println(list1.maxBy { it + 2 })
println(" ------ min -------")
println(list1.min()) // 返回集合中最小的元素
println(list1.minBy { it + 2 })
println(" ------ sum -------")
println(list1.sum())
println(list1.sumBy { it + 2 })
println(list1.sumByDouble { it.toDouble() })
println(" ------ average -----")
println(list1.average())
println(" ------ reduce -------")
println(list1.reduce { result, next -> result + next})
println(list1.reduceIndexed { index, result, next ->
index + result + next
})
println(list1.reduceRight { result, next -> result + next })
println(list1.reduceRightIndexed {index, result, next ->
index + result + next
})
println(" ------ fold -------")
println(list1.fold(3){result, next -> result + next})
println(list1.foldIndexed(3){index,result, next ->
index + result + next
})
println(list1.foldRight(3){result, next -> result + next})
println(list1.foldRightIndexed(3){index,result, next ->
index + result + next
})
复制代码
输出结果为:
------ any -------
true
false
------ all -------
false
------ none -------
false
false
------ max -------
5
5
------ min -------
1
1
------ sum -------
15
25
15.0
------ average -----
3.0
------ reduce -------
15
25
15
21
------ fold -------
18
28
18
28
复制代码
这篇文章篇幅很长,同时内容也不少。对于操做符讲解的不是很全,主要是介绍经常使用的操做符。而且对他们的含义即实现进行讲解。可是我相信您学习完上面的内容,对于集合的操做应该是得心印手了。同时了解了这些操做符是怎么实现的。
关于Kotlin
中对于集合的操做符,我推荐几篇别人的文章:
Kotlin系列之经常使用操做符
Kotlin入门第二课:集合操做
Kotlin集合与它的操做符们
上面几篇文章对于Kotlin
的所有操做符的介绍与使用讲解的很全面。而且都有例子去实现。
在这最后但愿您能给个关注,由于您的关注,是我继续写文章最好的动力。
个人我的博客:Jetictors
Github:Jteictors