Kotlin 學習筆記(8)-集合函數

Collection, List, Set, Map

Andy Lu
11 min readAug 24, 2020

目錄
1. List
2. MutableList
3. Set
4. MutableSet
5. Map
6. MutableMap

集合函數 (Collection) 是一種儲存一連串物件的方法,集合函數的繼承關係圖如下:

集合函數的繼承關係圖

主要有三個類別:

  • List:可儲存重複值,用索引值 (Index) 取值,為有序排列。
  • Set:儲存在 Set 的內容都是唯一的,為無序排列。
  • Map*:採用 Key-Value 的方式儲存,用 Key 可以取得 Value。

註:Map 雖然不是繼承 Collection,但仍歸納於集合函數內。

上面三個類別都是不可修改內容的,也就是說當 List Set Map 建立出來之後,就無法修改其內容了。但是,個別有一個可以繼承原類型可修改的類型:

  • MutableList:可修改的 List。
  • MutableSet:可修改的 Set。
  • MutableMap:可修改的Map。

List

可以儲存非重複項,每一個儲存在 List 的項目 (Element) 都含有一個 Index,Index 作為排序使用。

建立 List

  • listOf() :可以產生一組 List
val nameList: List<String> = listOf("Eli", "Mordoc", "Sophie")
  • 類型推斷:因為 listOf 裡面已經有內容,Kotlin 編譯器會自動判斷型別,所以可以將變數名稱後方的型別刪除。
val nameList = listOf("Eli", "Mordoc", "Sophie")

取值

  • [Index] : 利用中括弧加上索引值 (Index),即可快速地取得該位置的內容,需要注意的是,如果索引值的數值比 List 還大,就會拋出 ArrayIndexOutOfBoundsException
  • first() :可取得 List 第一個項目的值。
  • last() :可取得 List 最後一個項目的值。
val nameList = listOf("Eli", "Mordoc", "Sophie")
nameList[0] // Eli
nameList.first() // Eli
nameList.last() // Sophie
nameList[3] // ArrayIndexOutOfBoundsException

用中括弧取值,如果使用錯誤的索引值,會發生例外,Kotlin 提供了安全取值的方法:

  • getOrElse:取值,若取不到值,則回傳 Lambda 函式的回傳值。
  • getOrNull:取值,若取不到值,則回傳 null。
val forthName = nameList1.getOrElse(4) {"Not Found"} 
// Not Found
val forthName = nameList1.getOrNull(4)
//
Null
val forthName = nameList1.getOrNull(4) ?: "Not Found"
// Not Found

查詢內容是否存在

  • contains() : 代入一個欲查詢的項目,若存在則回傳 true ;反之,回傳 false
  • containsAll() : 代入一個欲查詢的集合,若存在則回傳 true ;反之,回傳 false
nameList.contains("Eli") // true 
nameList.contains("Andy") // false
nameList.containsAll(listOf("Sophie", "Mordoc")) //True

MutableList

  • 繼承 List ,增加了寫入的操作。

建立 MutableList

  • mutableListOf() :快速的建立可變 List,可以給予初始值,或是之後增加。
  • 如果給予初始值,Kotlin 會自動判斷型別。
val mutableList = mutableListOf("Tiger", "Lion", "Penguin")
  • 無給予初始值,無法自動判斷型,須提供型別,有下列兩種方式提供:
val mutableList = mutableLisOf<String>()val mutableList: MutableList<String> = mutableListOf()

修改內容

  • add(Element) : 在 List 的尾端加入 Element。
  • add(Index, Element) :在指定的 Index 加入 Element,Index 最大範圍為 List 的 大小。
  • remove(Element) :刪除 List 中的 Element 。
  • removeAt(Index) :刪除指定索引值的項目。
  • += Element : 在 List 的尾端加入 Element,與 add(Element) 功能相同。
  • [Index]=Updated Element :將指定位置的 Element 更改為 Updated Element。
  • clear() :清除 List 所有的項目。
val mutableList = mutableListOf("Tiger", "Lion", "Penguin") mutableList.add("Eagle") //[Tiger, Lion, Penguin, Eagle]

mutableList.remove("Tiger") //[Lion, Penguin, Eagle]
mutableList.removeAt(0) //[Penguin, Eagle]mutableList.add(0, "Tiger") //[Tiger, Penguin, Eagle]mutableList += "Jagar" //[Tiger, Penguin, Eagle, Jagar]mutableList[0] = "Lion" //[Lion, Penguin, Eagle, Jagar]mutableList.clear() // []

Set

  • 儲存在 Set 中的項目,都是唯一的,而且沒有順序。

建立 Set

  • 如同 List 類有 listOf ,Set 類也有 setOf

例:

val weekday = setOf("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
// [Monday, Tuesday, Wednesday, Thursday, Friday]
val weekday = setOf("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Friday")
// [Monday, Tuesday, Wednesday, Thursday, Friday]
  • 上例可以發現,第二個 setOf 定義了兩個 Friday,但是結果卻只有一個 Friday 存在 Set 中。

查詢內容是否存在

  • contains() : 代入一個欲查詢的項目,若存在則回傳 true ;反之,回傳 false
  • containsAll() : 代入一個欲查詢的集合,若存在則回傳 true ;反之,回傳 false

查詢特定位置的值

  • 前面提到, Set 沒有順序,所以查詢特定位置的值, Set 會走訪每一個項目找到值。
  • elementAt(n):可以取得第n個存入 set的項目。

MutableSet

  • MutableSet 繼承 Set,加上寫入的動作。

新增項目函數

  • add() :新增一個項目。
  • addAll() :新增多個項目。
  • += :新增一個項目。

刪除項目函數

  • remove() :刪除一個項目。
  • removeAll() :刪除多個項目。
  • -= :刪除一個項目。
  • clear() :清除所有項目。

distinct( ) = toSet( ) + toList( )

  • List 存放項目時會加上 index,藉由 index 可以快速的找到項目。
  • Set 存放唯一的項目,但是找尋項目比較慢。

兩種集合函數都有不同的用途,如果需要一個具有存放唯一值的 List,我們可以使用 toSet() 將 List 轉換成 Set,轉換之後重複的項目就會被刪除,接者使用 toList() ,則可以將 Set 在轉換成 List ,如此,就能擁有一個存放唯一值的 List。

Kotlin 在 List 函數中提供了另一個函數 distinct() 來簡化 toSet().toList()的動作,直接將 List 中重複的項目移除。

val items = listOf("Pen", "Pen", "Eraser").distinct()
//[Pen, Eraser]

迭代 (Iterator)

文章一開始的繼承關係圖,顯示 Collection 是繼承 Iterator ,那麼繼承 Collection 的 List 以及 Set 自然也有迭代的功能。

如何迭代?

方法1: for

for(SINGLE_ITEM in COLLECTION) : for 函數,括弧中間使用 in 關鍵字, in 左方擺放每一個讀出來的項目,右方擺放集合函數(Ex: List)

val animals = listOf("Pig", "Chicken", "OX")//Method: for for(animal in animals){
println("Here has $animal")
}
//Here has Pig
//Here has Chicken
//Here has OX

方法2: forEach

在每個集合函數,都有包含 forEach 函數,使用方法如下。
forEach 後方代入 Lambda 函數,在 Lamba 函數中,用 it 代表,每一次迭代中的值。

val animals = listOf("Pig", "Chicken", "OX")
//Method: forEach
animals.forEach {
println("Here has $it")
}
//Here has Pig
//Here has Chicken
//Here has OX

Map

介紹完 ListMap 之後,集合函數第三個就是 Map 了。

  • Map 是用 Key-Value 來儲存資料。一個 Key 對應到一個 Value,Key 不可重複,Value 可以重複。

建立一個Map

同樣地,Map 也有一個 mapOf 函數。

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3)
  • mapOf 裡,擺放的是 Key-Value,Kotlin 提供的一個直覺的寫法: KEY to VALUE ,用關鍵字 to 定義一組 Key-Value。
  • 另外,還可以使用 Pair(KEY, VALUE) 的形式來定義 Key-Value。
val val numbersMap = mapOf( 
Pair("key1", 1),
Pair("key2", 2),
Pair("key3", 3) )

讀取資料

  • [KEY] :回傳 Key 對應的值,若不存在則回傳 null。
  • getValue :回傳 Key 對應的值,若不存在則拋出例外 (NoSuchElementException)。
  • getOrElse :回傳 Key 對應的值,若不存在則用 Else lambda 取值。
  • getOrDefault :回傳 Key 對應的值,若不存在則回傳 Default 值。
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3) numbersMap["key1"] // 1 numbersMap.getValue("key4") // NoSuchElementException numbersMap.getOrElse("key4") { 0 } // 0 numbersMap.getOrDefault("key4", 0 ) //0

MutableMap

  • MutableMap 繼承 Map,加上寫入的動作。

修改資料

  • [KEY]=Value :若 Key 存在,更新原本的值,若 Key 不存在,新增一組 Key-Value。
  • += :同上。
  • putAll(COLLECTION) :以 Collection 類傳入,可同時加入多組 Key-Value。
  • remove(KEY) :若 Key 存在,則把該組 Key-Value 移除,並且回傳這個 Value;反之,若不存在,則回傳 null。
  • - KEY :若 Key 存在,則將 Key-Value 直接移除;反之,不移除任何項目,結束後回傳原Map。

結論

洋洋灑灑寫了一大篇,介紹了三種不同類型的集合函數,分別有各自的使用情境。
這邊歸納一下:
List :可以存放包含索引值的重複項目,可以快速的取值;
Set:存放不重複項,因內部實作方式,取值速度慢;
Map:存放 Key-Value 組合的數值,適合用在有對應關係的數值。

如果這篇文章有幫助到你,請拍手鼓勵我吧。

謝謝收看。

參考

Kotlinlang.org: Collections

Kotlin 權威2.0:Android 專家養成術 — 第十章、第十一章:List、Set 以及 Map

--

--

Andy Lu
Andy Lu

Written by Andy Lu

Android/Flutter developer, Kotlin Expert, like to learn and share.