1. 介紹
作為Kotlin入門的第三課剖效,打算直接學習至關重要的集合部分虎锚。因為一般的應用開發(fā)都離不開數(shù)據(jù),數(shù)據(jù)處理就要用到集合朴乖,而只有深入了解集合祖屏,包括概念及不同類型的集合分別實現(xiàn)了哪些方法,才能在需要的時候快速選出最合適的集合與對應的操作买羞。因此袁勺,迫不及待地想給大家展示Kotlin集合的魅力,基礎數(shù)據(jù)類型的用法會放到后續(xù)的文章進行整理畜普。
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. 操作方法
學習的同時通過編碼練習是很有必要的,除了加深理解還可以發(fā)現(xiàn)資料中存在的問題虽画,常見的如IDEA或API更新了而資料是舊的掠手,花時間去學習已經(jīng)廢棄的方法就不值得了。所以狸捕,建議英文好的通過官網(wǎng)給出的資料來學習是最好的喷鸽,上面的信息一般會及時更新。
先定義兩個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 總數(shù)操作
測試代碼:
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--查詢集合中滿足條件的元素個數(shù)混槐;
fold--在給定初始值的基礎上,從第一項到最后一項進行累加轩性;
foldRight--在給定初始值的基礎上声登,從最后一下到第一項進行累加,與fold只是的方向不同;
forEach--循環(huán)遍歷元素悯嗓,元素是it件舵,可對每個元素進行相關操作;
forEachIndexed--循環(huán)遍歷元素脯厨,同時得到元素index(下標)铅祸;
max--查詢最大的元素,如果沒有則返回null合武;
maxBy--獲取方法處理后返回結果最大值對應的那個元素的初始值临梗,如果沒有則返回null;
min--查詢最小的元素稼跳,如果沒有則返回null盟庞;
minBy--獲取方法處理后返回結果最小值對應那個元素的初始值,如果沒有則返回null汤善;
none--判斷集合中是否都不滿足條件什猖,是則返回true;
reduce--與fold區(qū)別在于沒有初始值萎津,或者說初始值為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大小時會出現(xiàn)異常揽惹;
take--返回從第一個開始的n個元素;
takeLast--返回從最后一個開始的n個元素四康;
takeWhile--返回不滿足條件的下標前面的所有元素的集合搪搏;
代碼中有一行注釋,關于slice操作箭养,在實際使用時需要注意過濾List中的元素值慕嚷,以免出現(xiàn)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--執(zhí)行方法轉換前過濾掉為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--查找下標對應元素仔夺,如果越界會根據(jù)方法返回默認值(最大下標經(jīng)方法后的值);
elementAtOrNull--查找下標對應元素攒砖,越界會返回Null缸兔;
first--返回符合條件的第一個元素,沒有則會拋NoSuchElementException異常吹艇;
firstOrNull--返回符合條件的第一個元素惰蜜,沒有返回null;
indexOf--返回指定下標的元素受神,沒有返回-1抛猖;
indexOfFirst--返回第一個符合條件的元素下標,沒有返回-1鼻听;
indexOfLast--返回最后一個符合條件的元素下標财著,沒有返回-1;
last--返回符合條件的最后一個元素精算,沒有則會拋NoSuchElementException異常瓢宦;
lastIndexOf--返回符合條件的最后一個元素,沒有返回-1灰羽;
lastOrNull--返回符合條件的最后一個元素驮履,沒有返回null鱼辙;
single--返回符合條件的單個元素,如有沒有符合的或符合超過一個分別會拋NoSuchElementException或IllegalArgumentException異常玫镐;
singleOrNull--返回符合條件的單個元素倒戏,如有沒有符合或超過一個,返回null恐似;
可以看到杜跷,容易出現(xiàn)異常的操作Kotlin會給出另一個安全調用的替代,如first與firstOrNull矫夷。
打印結果:
true
1
20
null
0
null
4
0
8
8
5
null
5
null
2.5 生產(chǎn)操作
測試代碼:
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--根據(jù)判斷條件是否成立葛闷,拆分成兩個Pair;
plus--合并兩個List双藕,可以用"+"替代淑趾;
zip--兩個集合按照下標組合成一個個的Pair塞到集合中返回;
unzip--將包含多個Pair的List轉換成含List的Pair忧陪;
Pair對象的數(shù)據(jù)組成形式為(first, secord)扣泊,即Pair(1, 2).first可以取出數(shù)據(jù)1。
注意:文檔和網(wǎng)上一些老的資料還提到了merge操作嘶摊,編碼時提示找不到符號延蟹,查資料發(fā)現(xiàn)從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--根據(jù)方法處理結果進行自然(升序)排序;
sortedDescending--降序排序蹂空;
sortedByDescending--根據(jù)方法處理結果進行降序排序俯萌;
注意:新版kotlin需要調用sorted()這樣帶"ed"后綴的方法才能返回List,而sort()是返回Unit上枕。那么這兩種方法還有哪些區(qū)別咐熙,或者說分別在什么場景下使用?
還是以sort為例辨萍,sorted()處理過程中會新建臨時的List來保存結果數(shù)據(jù)棋恼,對原來的調用者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打印出來發(fā)現(xiàn)果然還是初始化時的順序:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
3. 總結
本文對集合類型List(MutableList針對排序)的總數(shù)齐蔽、過濾、映射床估、元素含滴、生產(chǎn)及排序六種操作進行了測試,指出了可能出現(xiàn)異常的地方丐巫,通過比較加深了List和MutableList這種對應類型的聯(lián)系與區(qū)別谈况。有些操作在Kotlin中只需一句代碼就可以得到結果,而在Java中需要手動通過普通的循環(huán)或迭代器來對集合中的元素逐一進行處理递胧。
對于Set等其他集合類型碑韵,對象創(chuàng)建和操作與List類似,這里不一一舉出了谓着。