Kotlin入門第二課:集合操作


 

測試項目Github地址:

KotlinForJava

 

前文傳送:

Kotlin入門第一課:從對比Java開始

初次嘗試用Kotlin實現Android項目

 

1. 介紹

作為Kotlin入門的第二課,不打算按照教程從基礎數據類型開始,而是直接學習至關重要的集合部分。因為一般的應用開發都離不開數據,數據處理就要用到集合,而只有深入了解集合,包括概念及不同類型的集合分別實現了哪些方法,才能在需要的時候快速選出最合適的集合與對應的操作。因此,迫不及待地想給大家展示Kotlin集合的魅力,基礎數據類型的用法會放到后續的文章進行整理。

Kotlin中的集合主要有以下幾種:

Iterable--An iterator over a collection or another entity that can be represented as a sequence of elements;

MutableIterable--An iterator over a mutable collection. Provides the ability to remove elements while iterating;

Collection--A generic collection of elements. Methods in this interface support only read-only access to the collection;

MutableCollection--A generic collection of elements that supports adding and removing elements;

List--A generic ordered collection of elements. Methods in this interface support only read-only access to the list;

MutableList--A generic ordered collection of elements that supports adding and removing elements;

Set--A generic unordered collection of elements that does not support duplicate elements;

MutableSet--A generic unordered collection of elements that does not support duplicate elements, and supports adding and removing elements;

Map--A collection that holds pairs of objects (keys and values) and supports efficiently retrieving the value corresponding to each key. Map keys are unique; the map holds only one value for each key;

MutableMap--A modifiable collection that holds pairs of objects (keys and values) and supports efficiently retrieving the value corresponding to each key. Map keys are unique; the map holds only one value for each key;

不專業的翻譯會誤導讀者,所以這里就不獻丑了,相信這段英文解釋對程序員來說不成問題。

 

2. 操作方法

涉及到的代碼在KotlinForJava的Kotlin1項目中,針對集合List和MutableList的操作進行測試,參考的是Kotlin中文學習資料,前面給出的文章中能找到相應的資源鏈接。

學習的同時通過編碼練習是很有必要的,除了加深理解還可以發現資料中存在的問題,常見的如IDEA或API更新了而資料是舊的,花時間去學習已經廢棄的方法就不值得了。所以,建議英文好的通過官網給出的資料來學習是最好的,上面的信息一般會及時更新。

先定義兩個List對象,后面的操作會用到。

1 val list = listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
2 val mutableList = mutableListOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

 2.1 總數操作

測試代碼:

 1 println(list.any { it % 2 == 1 })
 2 
 3 println(list.all { it % 2 == 1 })
 4 
 5 println(list.count { it % 2 == 1 })
 6 
 7 println(list.fold(10) { total, next -> total + next })
 8 println(list.foldRight(10) { total, next -> total + next })
 9 
10 list.forEach { value -> if (value > 8) println(value) }
11 list.forEachIndexed { index, value -> if (value > 8) println("value of index $index is $value") }
12 
13 println(list.max())
14 println(list.maxBy { -it })
15 
16 println(list.min())
17 println(list.minBy { -it })
18 
19 println(list.none { it % 2 == 10 })
20 
21 println(list.reduce { total, next -> total + next })
22 println(list.reduceRight { total, next -> total + next })
23 
24 println(list.sumBy { it % 2 })

方法作用:

any--判斷集合中是否有滿足條件 的元素;

all--判斷集合中的元素是否都滿足條件;

count--查詢集合中滿足條件的元素個數;

fold--在給定初始值的基礎上,從第一項到最后一項進行累加;
foldRight--在給定初始值的基礎上,從最后一下到第一項進行累加,與fold只是的方向不同;

forEach--循環遍歷元素,元素是it,可對每個元素進行相關操作;
forEachIndexed--循環遍歷元素,同時得到元素index(下標);

max--查詢最大的元素,如果沒有則返回null;
maxBy--獲取方法處理后返回結果最大值對應的那個元素的初始值,如果沒有則返回null;

min--查詢最小的元素,如果沒有則返回null;
minBy--獲取方法處理后返回結果最小值對應那個元素的初始值,如果沒有則返回null;

none--判斷集合中是否都不滿足條件,是則返回true;

reduce--與fold區別在於沒有初始值,或者說初始值為0,從第一項到最后一項進行累加;
reduceRight--從最后一項到第一項進行累加,與reduce只是方向的不同;

sumBy--獲取方法處理后返回結果值的總和;

建議將文字解釋和代碼結合起來理解方法的作用,先對結果有一個預判,然后看下面的打印信息。

打印結果:

true
false
5
55
55
9
value of index 9 is 9
9
0
0
9
true
45
45
5

 2.2 過濾操作

測試代碼:

 1 println(list.drop(4))
 2 println(list.dropWhile { it < 9 })
 3 println(list.dropLastWhile { it < 9 })
 4 
 5 println(list.filter { it % 2 == 0 })
 6 println(list.filterNot { it % 2 == 0 })
 7 println(list.filterNotNull())
 8 
 9 println(list.slice(listOf(0, 4, 8)))
10 //println(list.slice(listOf(0, 4, 80)))  //java.lang.ArrayIndexOutOfBoundsException: 80
11 
12 println(list.take(2))
13 println(list.takeLast(2))
14 println(list.takeWhile { it < 3 })

方法作用:

drop--返回去掉前n個元素后的列表;
dropWhile--返回從第一項起,去掉滿足條件的元素,直到不滿足條件的一項為止;
dropLastWhile--返回從最后一項起,去掉滿足條件的元素,直到不滿足條件的一項為止;

filter--過濾掉所有不滿足條件的元素;
filterNot--過濾掉所有滿足條件的元素;
filterNotNull--過濾掉所有值為null的元素;

slice--過濾掉非指定下標的元素,即保留下標對應的元素過濾List中指定下標的元素(比如這里只保留下標為1,3,4的元素),當過濾list中有元素值大於目標List大小時會出現異常;

take--返回從第一個開始的n個元素;
takeLast--返回從最后一個開始的n個元素;
takeWhile--返回不滿足條件的下標前面的所有元素的集合;

代碼中有一行注釋,關於slice操作,在實際使用時需要注意過濾List中的元素值,以免出現ArrayIndexOutOfBoundsException異常。

打印結果:

[4, 5, 6, 7, 8, 9]
[9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 2, 4, 6, 8]
[1, 3, 5, 7, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 4, 8]
[0, 1]
[8, 9]
[0, 1, 2]

2.3 映射操作

測試代碼:

1 println(list.flatMap { listOf(it, it + 1) })
2 
3 println(list.groupBy { if (it % 2 == 0) "even" else "odd" })
4 
5 println(list.map { it * 2 })
6 println(list.mapIndexed { index, it -> index * it })
7 println(list.mapNotNull { it * 2 })

方法作用:

flatMap--合並兩個集合,可以在合並的時候對迭代元素值it多想要的操作;

groupBy--將集合中的元素按照某個條件分組,返回Map;

map--將集合中的元素通過某個方法轉換后的結果存到一個集合中;
mapIndexed--除了得到轉換后的結果,還可以拿到index(下標);
mapNotNull--執行方法轉換前過濾掉為null的元素;

打印結果:

[0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10]
{even=[0, 2, 4, 6, 8], odd=[1, 3, 5, 7, 9]}
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

2.4 元素操作

測試代碼:

 1 println(list.contains(2))
 2 
 3 println(list.elementAt(1))
 4 //println(list.elementAt(11))  //java.lang.ArrayIndexOutOfBoundsException: 11
 5 println(list.elementAtOrElse(10, { 2 * it }))
 6 println(list.elementAtOrNull(10))
 7 
 8 println(list.first { it % 2 == 0 })
 9 //println(list.first { it % 2 == 10 })  //java.util.NoSuchElementException: Collection contains no element matching the predicate
10 println(list.firstOrNull() { it % 2 == 10 })
11 
12 println(list.indexOf(4))
13 println(list.indexOfFirst { it % 2 == 0 })
14 println(list.indexOfLast { it % 2 == 0 })
15 
16 println(list.last { it % 2 == 0 })
17 //println(list.last { it % 2 == 10 })  //java.util.NoSuchElementException: List contains no element matching the predicate
18 println(list.lastIndexOf(5))
19 println(list.lastOrNull { it % 2 == 10 })
20 
21 println(list.single { it % 6 == 5 })
22 //println(list.single { it % 2 == 0 })  //java.lang.IllegalArgumentException: Collection contains more than one matching element
23 println(list.singleOrNull() { it % 5 == 10 })

方法作用:

contains--判斷集合中是否有指定元素,有則返回true;

elementAt--查找下標對應的元素,如果下標越界會拋IndexOutOfBoundsException異常;
elementAtOrElse--查找下標對應元素,如果越界會根據方法返回默認值(最大下標經方法后的值);
elementAtOrNull--查找下標對應元素,越界會返回Null;

first--返回符合條件的第一個元素,沒有則會拋NoSuchElementException異常;
firstOrNull--返回符合條件的第一個元素,沒有返回null;

indexOf--返回指定下標的元素,沒有返回-1;
indexOfFirst--返回第一個符合條件的元素下標,沒有返回-1;
indexOfLast--返回最后一個符合條件的元素下標,沒有返回-1;

last--返回符合條件的最后一個元素,沒有則會拋NoSuchElementException異常;
lastIndexOf--返回符合條件的最后一個元素,沒有返回-1;
lastOrNull--返回符合條件的最后一個元素,沒有返回null;

single--返回符合條件的單個元素,如有沒有符合的或符合超過一個分別會拋NoSuchElementException或IllegalArgumentException異常;
singleOrNull--返回符合條件的單個元素,如有沒有符合或超過一個,返回null;

可以看到,容易出現異常的操作Kotlin會給出另一個安全調用的替代,如first與firstOrNull。

打印結果:

true
1
20
null
0
null
4
0
8
8
5
null
5
null

2.5 生產操作

測試代碼:

1 println(list.partition { it % 2 == 0 })
2 
3 println(list + listOf(10, 11))
4 
5 println(list.zip(listOf(7, 8)))
6 println(listOf(Pair(5, 7), Pair(6, 8)).unzip())

方法作用:

partition--根據判斷條件是否成立,拆分成兩個Pair;

plus--合並兩個List,可以用"+"替代;

zip--兩個集合按照下標組合成一個個的Pair塞到集合中返回;
unzip--將包含多個Pair的List轉換成含List的Pair;

Pair對象的數據組成形式為(first, secord),即Pair(1, 2).first可以取出數據1。

注意:文檔和網上一些老的資料還提到了merge操作,編碼時提示找不到符號,查資料發現從Kotlin 1.0 Beta 2后的版本開始就棄用了。

打印結果:

([0, 2, 4, 6, 8], [1, 3, 5, 7, 9])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
[(0, 7), (1, 8)]
([5, 6], [7, 8])

2.6 排序操作

測試代碼:

1 println(list.reversed())
2 
3 println(list.sorted())
4 println(list.sortedBy {it % 3})
5 
6 println(list.sortedDescending())
7 println(list.sortedByDescending { it % 3 })

方法作用:

reversed--相反順序;
sorted--自然排序(升序);
sortedBy--根據方法處理結果進行自然(升序)排序;
sortedDescending--降序排序;
sortedByDescending--根據方法處理結果進行降序排序;

注意:新版kotlin需要調用sorted()這樣帶"ed"后綴的方法才能返回List,而sort()是返回Unit。那么這兩種方法還有哪些區別,或者說分別在什么場景下使用?

還是以sort為例,sorted()處理過程中會新建臨時的List來保存結果數據,對原來的調用者List不會做任何改變,所以需要將新建的對象返回;而sort()是在原來的List基礎上進行元素順序的調整,不會新建對象,所以不需要返回List。

打印結果:

[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 3, 6, 9, 1, 4, 7, 2, 5, 8]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
[2, 5, 8, 1, 4, 7, 0, 3, 6, 9]

開頭部分還定義了一個MutableList對象,下面就結合不帶"ed"后綴的排序方法對其進行操作。

1 mutableList.reverse()
2 println(mutableList)

打印輸出:

[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

如果用list對象調用reverse()會提示List沒有該方法,算是各盡其職。而將list打印出來發現果然還是初始化時的順序:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 

3. 總結

本文對集合類型List(MutableList針對排序)的總數、過濾、映射、元素、生產及排序六種操作進行了測試,指出了可能出現異常的地方,通過比較加深了List和MutableList這種對應類型的聯系與區別。有些操作在Kotlin中只需一句代碼就可以得到結果,而在Java中需要手動通過普通的循環或迭代器來對集合中的元素逐一進行處理。

對於Set等其他集合類型,對象創建和操作與List類似,這里不一一舉出了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM