上一章我們討論的都是如何「讀取」 Collection 裡的元素,不過更多時候我們需要「修改」Collection 裡的內容,也就是如何新增元素到 Collection 裡、怎麼移除 Collection 裡指定的元素、該怎樣更新 Collection 裡的元素等。不過要特別注意的是,因為這個章節裡討論的都會改變 Collection 的大小或內容,所以大多數的操作都是基於 Mutable 的 List,少部份也適用於 Set 及 Map。
Collection 新增元素的 API 命名很直覺,就是 add(element)
,然後把要放進 Collection 的 element
當參數傳入即可,傳入的 element 預設就放到 Collection 的最後一格。若是想要指定要放到 Collection 的哪一格,則可以改用 add(index, element)
指定 element 要放置的 index 為何。
val mutableListOfNumbers = mutableListOf(1, 3, 5, 6, 7)
mutableListOfNumbers.add(8) // [1, 3, 5, 6, 7, 8]
mutableListOfNumbers.add(6, 999) // [1, 3, 5, 999, 6, 7, 8]
不過在指定 index 時,也要注意別超出邊界,不然執行時會拋出 IndexOutOfBoundsException
喔!假如一次想要增加很多個 element 的話,可以用 addAll(elements)
,傳入一個 Collection 參數即可,若有需要一樣可以用 addAll(index, elements)
指定插入位置。
val mutableListOfNumbers = mutableListOf(1, 3, 5, 6, 7)
mutableListOfNumbers.addAll(listOf(2, 4, 9)) // [1, 3, 5, 6, 7, 2, 4, 9]
mutableListOfNumbers.addAll(0, listOf(2, 4, 9)) // [20, 40, 90, 1, 3, 5, 6, 7, 2, 4, 9]
一個比較特別的寫法是用 +=
來新增元素,作用跟 add(element)
及 addAll(element)
一樣,都是將元素新增在 Collection 最後。
val mutableListOfNames = mutableListOf("Eli", "Mordoc", "Sophie")
mutableListOfNames += "Reginald" // [Eli, Mordoc, Sophie, Reginald]
mutableListOfNames += listOf("Alex", "Shruti") // [Eli, Mordoc, Sophie, Reginald, Alex, Shruti]
操作 Collection 時大多會以 index 來指定位置,所以可以很直覺得用 [index]
來指定要更新哪個位置的元素,Kotlin 也有提供像 set(index, element)
這種型式的 API 供我們使用,傳入要更新的 index 位置及更新的內容即可。不過一樣要注意 index 是否有越界的問題,以免程式拋出例外。
val mutableListOfNumbers = mutableListOf(1, 3, 5, 6, 7)
mutableListOfNumbers[0] = 100 // [100, 3, 5, 6, 7]
mutableListOfNumbers.set(1, 200) // [100, 200, 5, 6, 7]
Collection 還提供了 replaceAll()
這個 API,你可以傳入一個 Lambda 來更新所有的元素內容。
val mutableListOfNumbers = mutableListOf(1, 3, 5, 6, 7)
// mutableListOfNumbers.replaceAll() // 還不會用…
mutableListOfNumbers.replaceAll{ it * 2 } // [2, 6, 10, 12, 14]
要刪除 Collection 內的元素,Kotlin 提供了非常多種 API 供不同情境下使用。開頭是 remove
的 API 就有數個,remove(element)
是用 element 來尋找後刪除、removeAt(index)
則是用 index 來尋找後刪除。
val mutableListOfNumbers = mutableListOf(1, 3, 5, 6, 7)
mutableListOfNumbers.remove(3) // [1, 5, 6, 7]
mutableListOfNumbers.removeAt(0) // [5, 6, 7]
Kotlin 的標準函式庫也提供 removeFirst()
及 removeLast()
來刪除 Collection 的第一個或最後一個元素並回傳。另外,考量到 Collection 有可能是空的,也有對應的 removeFirstOrNull()
及 removeLastOrNull()
會在 Collection 是空的時候不觸發 Exception 而是回傳 null。
val shopping = mutableListOf("Tea", "Eggs", "Sugar")
val first = shopping.removeFirst()
// shopping 是 [Eggs, Sugar]
// first 是 Tea
val emptyShoppingList = mutableListOf<String>()
val first = emptyShoppingList.removeFirstOrNull()
// emptyShoppingList 是 []
// first 是 null
val shopping = mutableListOf("Tea", "Eggs", "Sugar")
val last = shopping.removeLast()
// shopping 是 [Tea, Eggs]
// last 是 Sugar
val emptyShoppingList = mutableListOf<String>()
val last = emptyShoppingList.removeLastOrNull()
// emptyShoppingList 是 []
// last 是 null
若是要刪除 Collection 內數個元素,可以用 removeAll(elements)
、若是反過來要「保留」某些元素的話,則可以用 retainAll(elements)
val shopping = mutableListOf("Tea", "Eggs", "Sugar")
shopping.removeAll(listOf("Milk", "Sugar")) // [Tea, Eggs]
val anotherShopping = mutableListOf("Tea", "Eggs", "Sugar")
anotherShopping.retainAll(listOf("Tea", "Sugar") // [Tea, Sugar]
順帶一提,Collection 也支援 -=
刪除元素運算子,用來刪除 Collection 的某個元素,或從清單刪除 Collection 所列元素。依不同情境,用法如同 remove()
及 removeAll()
。
mutableListOf("Eli", "Mordoc", "Sophie") -= "Eli"
// ["Mordoc", "Sophie"]
val listOfNames = mutableListOf("Eli", "Mordoc", "Sophie")
listOfNames -= listOf("Eli", "Mordoc")
// ["Sophie"]
在刪除元素的過程中,也可以設定一些「條件」,比方說 removeIf()
、removeAll()
及 retainAll()
可以傳入一個 Lambda,這個 Lambda 裡帶著一個判斷邏輯,結果是 true 的就會被移除。
val listOfNames = mutableListOf("Eli", "Mordoc", "Sophie")
listOfNames.removeIf { it.contains("o") }
// [Eli]
val shopping = mutableListOf("Tea", "Eggs", "Sugar")
shopping.removeAll { it.contains('g') }
// [Tea]
val anotherShopping = mutableListOf("Tea", "Eggs", "Sugar")
anotherShopping.retainAll { it.contains('g') }
// [Eggs, Sugar]
當然,你也可以開大絕,直接用 clear()
清空整個 Collection!
val mutableListOfNumbers = mutableListOf(1, 3, 5, 6, 7)
mutableListOfNumbers.clear()
因為 Collection 橫跨 Array、List、Set、Map 等四種類別,不是所有 API 都能在每個類別上實作,在使用前務必要確定正在操作的這個類別是否有這個 API 可以使用,才不會發生預期之外的行為喔!以下用表格快速整理本篇文章裡提到的所有方式:
行為 | Array | MutableList | Set | Map | |
---|---|---|---|---|---|
+= | 新增元素 | x | v | v | x |
add(element) | 新增元素 | x | v | v | x |
add(index, element) | 在指定位置新增元素 | x | v | x | x |
addAll(elements) | 新增多個元素 | x | v | v | x |
addAll(index, elements) | 在指定位置新增多個元素 | x | v | x | x |
行為 | Array | MutableList | MutableSet | MutableMap | |
---|---|---|---|---|---|
[index] | 更新指定位置的元素 | v | v | x | v |
set(index, element) | 更新指定位置的元素 | v | v | x | v |
replaceAll{} | 用 λ 取代元素 | x | v | x | v |
行為 | Array | MutableList | MutableSet | MutableMap | |
---|---|---|---|---|---|
-= | 刪除一個或多個元素 | x | v | v | v |
remove(element) | 刪除指定元素 | x | v | v | v |
removeAt(index) | 刪除指定位置的元素 | x | v | x | x |
removeAll(elements) | 刪除指定的多個元素 | x | v | v | x |
removeAll {} | 用 λ 刪除元素 | x | v | v | x |
removeIf {} | 刪除 | x | v | v | x |
retainAll(elements) | 保留指定的多個元素 | x | v | v | x |
retainAll{} | 用 λ 保留元素 | x | v | v | x |
removeFirst() | 刪除第一個元素 | x | v | x | x |
removeFirstOrNull() | 刪除第一個元素,若元素是 empty 則回傳 null | x | v | x | x |
removeLast() | 刪除最後一個元素 | x | v | x | x |
removeLastOrNull() | 刪除最後一個元素,若元素是 empty 則回傳 null | x | v | x | x |
clear() | 清空 | x | v | v | v |