讓我們的東西照規矩來!

我們前面有學到陣列,並且也使用陣列示範了不少事情(尤其是在for迴圈的時候),我們可以體會到陣列可以拿來快速的儲存一堆相同類型的東西,並且做簡單的運算,例如:

  • 取得陣列大小

  • 將陣列的順序倒過來

  • 確認某個東西有沒有在陣列裡面

  • 計算陣列所有東西的總和(如果裡面保存的是數值的話)

  • 計算平均值(如果裡面保存的是數值的話)

  • 找到最大值或最小值

  • 排序

// 取得陣列大小
array.size
// 將陣列的順序倒過來
array.reverse()
// 確認某個東西有沒有在陣列裡面
1 in array
// 計算陣列所有東西的總和(如果裡面保存的是數值的話)
array.sum()
// 計算平均值(如果裡面保存的是數值的話)
array.average()
// 找到最大值或最小值
array.max()
array.min()
// 排序
array.sort()

可是陣列能做到的事情還是很有限,陣列還是有一些重要的功能沒辦法做到:

  • 我們沒有辦法改變陣列的大小

  • 陣列裡面的數值隨時都暴露在可能被改變的風險當中

那Kotlin裡面有什麼東西可以解決這兩個問題呢?

List、Set、Map!

在Kotlin裡面有三種常用的集合:List、Set、Map,我們會依照需求不一樣選擇我們需要使用的集合:

List - 當順序很重要的時候

List跟Array一樣具有索引值,順序在List裡面是很重要的東西,可以讓我們很清楚的知道什麼東西在哪裡

Set - 當獨特性很重要的時候

跟List不同的是,Set並不在乎裡面的順序,但是Set裡面的東西絕對不會重複

Map - 當用Key來尋找東西很重要的時候

Map使用Key/Value的格式儲存資料,我們可以很輕易的使用Key值找到Value物件

接下來我們就依序來介紹他們

有序的List

我們可以使用跟建立array差不多的方式建立list:

val students: List<String> = listOf("小黑", "小固", "白助")

我們可以像這樣完整的宣告一個List,當然我們也可以使用型別推斷,省略掉 List<String> 不寫

我可以取得List裡面的某個值

val students: List<String> = listOf("小黑", "小固", "白助")
println(students[1])

可以檢查List裡面有沒有包含某個值

val students: List<String> = listOf("小黑", "小固", "白助")
println("白助" in students)
println(students.contains("白助"))

也可以使用for迴圈遍歷List的所有項目

val students: List<String> = listOf("小黑", "小固", "白助")
for (student in students) {
    println(student)
}

或是取得某一個元素的索引值

val students: List<String> = listOf("小黑", "小固", "白助")
println(students.indexOf("白助"))

可被更改的MutableList

List一被建立之後就沒辦法被更改,如果我們需要修改List的值的話,我們就要使用到MutableList。MutableList擁有前面List可以被使用的所有功能,另外還多了一些其他的使用方式:

加入元素

val students = mutableListOf("小黑", "小固", "白助")
students.add("小克")
students.add(2, "黑皮")

移除元素

val students = mutableListOf("小黑", "小固", "白助")
students.remove("白助")
students.removeAt(0)

更改元素

val students = mutableListOf("小黑", "小固", "白助")
students[2] = "威威"

還有很多可以使用的東西......

val students = mutableListOf("小黑", "小固", "白助")
    // 排序
    students.sort()
    students.sorted()
    students.sortDescending()
    students.sortedDescending()
    // 倒過來
    students.reverse()
    students.reversed()
    
    val anotherStudents = mutableListOf("小黑", "威威", "小固")
    // 新增一堆東西
    students.addAll(anotherStudents)
    // 刪除一堆東西
    students.removeAll(anotherStudents)
    // 保留某些東西
    students.retainAll(anotherStudents)
    // 清除
    students.clear()
    // 互相轉換
    val list: List<String> = students.toList()
    val mutableList: MutableList<String> = list.toMutableList()

List可以允許重複的值,可是如果今天我們想要每一個東西都獨一無二的時候,List就沒辦法跟我們掛保證,這個時候就輪到Set出場了

獨一無二的Set

Set裡面不允許重複的值,我們可以這樣使用Set:

val students = setOf("小黑", "小固", "白助", "小黑", "威威", "威威")
// 檢查有沒有特定的值
println("白助" in students)
println(students.contains("白助"))
// 遍歷Set
for (student in students) {
    println(student)
}

什麼叫做“重複”?

在說明什麼是重複之前我們得先認識什麼是雜湊碼

雜湊碼(hashCode)

雜湊碼是物件透過一系列的演算方法產生的值(在Kotlin裡面使用hashCode函數得到的雜湊碼為 Int),理想上每一個物件都應該有獨一無二的雜湊碼,可是現實上卻沒辦法做到完全的獨一無二。就算是不同的物件,還是有低機率產生相同的雜湊碼。依照這個特性我們可以得出一個結論:雜湊碼不一樣的兩個物件一定是不同的物件。

Set會先使用雜湊碼做比對,如果發現兩個物件的雜湊碼相同的話,就會需要做進一步的比對

===

接下來會使用“===”檢查兩個物件是否是同一個實體,如果這個時候檢查到兩個物件是同樣的實體就會判定為相同物件。如果這時候判定為不同實體就會再進行下一步

equals(==)

最後會使用==檢查兩個物件,如果回傳true則兩個為相同物件,回傳false則為不同物件

我們現在已經了解了怎麼樣判斷物件是否相同的方法了,雖然我們現在還沒有學會怎麼自定義物件,但是我們可以先知道在定義物件的時候,如果要比較是否相等的時候需要注意的準則:

  • 如果兩個物件是相等的,他們必須要有相同的雜湊碼

  • 如果兩個物件是相等的,則呼叫equals必須要是true

  • 如果我們覆寫了equals,就必須要一起覆寫hashCode

可被更改的MutableSet

mutableSet裡面有幾個很熟悉的函數可以使用:

val students = mutableSetOf("小黑", "小固", "白助", "小黑", "威威", "威威")
students.add("黑皮")
students.remove("白助")

val anotherStudents = setOf("威威", "小固", "黑皮")
students.addAll(anotherStudents)
students.removeAll(anotherStudents)
students.retainAll(anotherStudents)

students.clear()

val set: Set<String> = students.toSet()
val mutableSet: MutableSet<String> = set.toMutableSet()

使用Key/Value的Map

Map使用Key/Value對應的型態來儲存物件,Key值有點類似於List裡面的index值,只不過Key值不僅限於Int型態,而且也不需要是連續的,唯一的要求是Key值不可以重複:

val students = mapOf(
    "TIP101-01" to "小黑",
    "TIP101-02" to "小固",
    "TIP101-02" to "白助",
    "TIP101-03" to "黑皮"
)
// 檢查有沒有某個Key值
println(students.containsKey("TIP101-01"))
// 檢查有沒有某個Value值
println(students.containsValue("小固"))
// 利用Key取出某個值
println(students["TIP101-01"])
// 遍歷每一對Key/Value值
for ((id, student) in students) {
    println("$id: $student")
}

可被更改的MutableMap

可以在Map裡面使用的東西變少了,不過功能上是差不多的

val students = mutableMapOf(
    "TIP101-01" to "小黑",
    "TIP101-02" to "小固",
    "TIP101-02" to "白助",
    "TIP101-03" to "黑皮"
)
// 新增
students["TIP101-04"] = "白助"
// 修改
students["TIP101-02"] = "小固"
// 刪除
students.remove("TIP101-03")
students.remove("TIP101-01", "小黑")
// 新增多個
val anotherStudents = mapOf(
    "TIP101-05" to "威威",
    "TIP101-06" to "小克"
)
students.putAll(anotherStudents)
// 清除
students.clear()
val map = students.toMap()
val mutableMap = map.toMutableMap()

Last updated