iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 6
0

集合(Collections)是可以儲存一群相同型別資料的物件,Kotlin 集合類型主要有 ListSetMap,又可再細分為可變(mutable )集合不可變(immutable)集合, Kotlin 官方這邊有提供一張 Collection 結構圖(參考 Kotlin 官方文件):

https://ithelp.ithome.com.tw/upload/images/20200915/20121179jcIlfB7fvR.png

我們可以從上圖觀察出 Collection 是集合結構的根節點 root,而 Collection 還繼承了 Iterable interface ,其中 IterableCollectionListSetMap 都會再延伸出可變(Mutable)集合,清楚表達出集合成員們的關係。

Collection 既然作為根節點,我們可以觀察它內部是如何定義,下圖會發現它的內部除了繼承 Iterable 以外,也包含了 sizeisEmptycontainsoverride iterator 迭代元素的操作:

https://ithelp.ithome.com.tw/upload/images/20200915/20121179l4vP4g08Is.png

我們利用一個範例進行測試,在下面範例中我們先定義一個 List 與一個 Set 的集合,再定義一個參數為 Collection 的函數,觀察兩者是否會印出一樣的值:

fun main() {
	// 定義一個 List 集合
    val stringList = listOf("one", "two", "three")
    printAll(stringList) // 印出 one two three 

	// 定義一個 Set 集合
    val stringSet = setOf("one", "two", "three")
    printAll(stringSet) // 印出 one two three
}

fun printAll(strings: Collection<String>) {
    for(s in strings) print("$s ")
    println()
}

集合類型

  • List 是一個有序集合,可利用索引來存取項目(item)資料,同樣的項目數值在 list 中可重複出現多次

    fun main() {
        val numbers = listOf(1, 4, 3, 4)
        // 印出集合共有幾個元素
        println("集合共有 ${numbers.size} 個元素")
    
        // 索引起始值為 0,故 get(2) 是取得第三個數值
        println("第三個元素為 ${numbers.get(2)}")
    
        // 同上,索引起始值為 0,故 numbers[3] 是取得第四個數值
        println("第四個元素為 ${numbers[3]}") 
    
        // 數值 3 所在索引值為 2
        println("利用數值找出所在的索引值 ${numbers.indexOf(3)}")  
    
        // 此段程式會印出下列訊息:
        // 集合共有 4 個元素
        // 第三個元素為 3
        // 第四個元素為 4
        // 利用數值找出所在的索引值 2
    }
    
  • Set 是一個無序集合,與 List 最大差別在於 Set 不可儲存重複數值項目,對於 Set 來說,元素的顺序並不重要

    fun main() {
        val numbers = setOf<Int>(1, 4, 3, 4)
    
        // 因 set 集合元素值不會重複,故 size 會為 3
        println("集合共有 ${numbers.size} 個元素") 
    
        // 回傳 true
        println("集合是否存在 3 的元素 ${numbers.contains(3)}") 
    
        // 印出下列訊息:
        // 集合共有 3 個元素
        // 集合是否存在 3 的元素 true
    }
    
  • Map 是由鍵值(Key)數值(Value)所組成的集合,Key 必須符合唯一性,每個 Key 值都會搭配一個 Value

    fun main() {
        val numbers = mapOf<String, Int>("key1" to 1, "key2" to 4, "key3" to  3, "key4" to  4)
        println("集合共有 ${numbers.size} 個元素")
    
        // 檢查是否有該索引值,若存在則回傳 true
        println("集合是否存在 key2 的索引值 ${"key2" in numbers}") 
    
        // 檢查是否有該數值,若有則回傳 true
        println("集合是否存在 4 的數值 ${numbers.containsValue(4)}") 
    
        // 印出下列訊息:
        // 集合共有 4 個元素
        // 集合是否存在 key2 的索引值 true
        // 集合是否存在 4 的數值 true
    }
    

可變(mutable)與不可變(immutable)

在文章開頭有提到, Kotlin 在集合這塊會再細分為可變(mutable)集合不可變(immutable)集合,依照文章開頭的 Kotlin 官方集合結構圖會發現,所有的可變集合都是繼承自不可變的集合,兩者只差在可變集合可以改變原集合的元素數值、順序、數量等,而不可變集合只能對元素進行讀取和查詢,我們利用下面範例進行測試:

fun main() {
    // 定義一個不可變集合 List,將無法針對內容修改
    val list = listOf(1, 2, 3, 4) 
    
    // 定義一個可變集合 mutableList,此集合可修改內容
    val mutableList = mutableListOf(1, 2, 3, 4) 

    list[0] = 1 // 此行會出現編譯錯誤,錯誤訊息可參考下圖
    mutableList[0] = 5  // 成功編譯
}

編譯錯誤可參考下圖訊息,會發現到 list 集合無法修改內容:
https://ithelp.ithome.com.tw/upload/images/20200915/201211791zQUFsuHwr.png

集合操作

在實務開發中,我們經常會遇到產品的某個業務邏輯問題需要操作集合,此時就會需要了解集合的操作方式,像是如何建立一個空集合、如何加入元素到集合、如何進行集合複製、如何逐步印出集合內所有元素、如何在集合取得特定條件的元素等方法,我們利用一個範例進行深入探討:

fun main() {
    
    // 建立一個空集合 List
    val list: MutableList<Int> = mutableListOf<Int>() 
    list.add(1) // 加入元素 1
    list.add(2) // 加入元素 2
    list.add(3) // 加入元素 3
    list.add(4) // 加入元素 4

    // 此段會進行集合複製,利用 toMutableList() 方法
    val copyList = list.toMutableList() 

	// 嘗試印出 copyList 共有幾個元素,此段會印出 「copyList 有 4 個元素」
    println("copyList 有 ${copyList.size} 個元素") 

    // 嘗試利用 forEach 方法逐步印出集合內元素,結果印出「1 2 3 4 」結果
    copyList.forEach { print("$it ") } 

	// 嘗試利用 filter 方法加入偶數判斷條件,印出「2 4」結果
    copyList.filter { it % 2 == 0 }.forEach { print("$it ") } 

	println("集合取值方法")
    
    // slice 是利用區間索引值進行取值,此行會印出 [2, 3, 4]
    println(copyList.slice(1..3)) 
    
    // take 是取得0-2的元素,此行會印出 [1, 2]
    println(copyList.take(2))     
    
    // takeList 則是取得倒數0-2的元素,此行會印出 [3, 4]
    println(copyList.takeLast(2)) 
    
    // drop 會回傳指定索引的後面全部元素,此行會印出 [3, 4]
    println(copyList.drop(2))     
    
    // 此段會印出 copyList 共有 4 個元素
    println("copyList 有 ${copyList.size} 個元素") 
}

Reference


上一篇
[Day 05] 遠征 Kotlin × 函數介紹
下一篇
[Day 07] 遠征 Kotlin × 類別與物件
系列文
30天從零撰寫 Kotlin 語言並應用於 Spring Boot 開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言