在上一篇文章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