[Day 20] Set

Set

Set 也一樣分成

  • 只可讀的 Set
  • 可以修改的 Mutable Set

跟 List 用途不同, Set 特性如下

  • 不能透過 index 取得資料
  • 資料是唯一的,會去掉重複的資料

不可修改的 Set

只能讀取,不能修改內容,Kotlin 的 Set 底層是 Java 的 LinkedHashSet,資料是按照加入順序進行排列的有序集合

setOf()

創造方式如下,使用 setOf()

val intSet = setOf(3, 1, 2, 3)
println(intSet) // [3, 1, 2]

或是 list.toSet()

val muList = mutableListOf("tim", "andy", "ann")
val set = muList.toSet()
println(set) // [tim, andy, ann]

以上結果都會去除重複的值,結果會是當初資料加入的順序

可以修改的 Mutable Set

mutableSetOf() 或 list.toMutableSet()

用法差不多,只是 set 可以做修改

// mutableSet
val intMuSet = mutableSetOf(3, 1, 2, 3)
println(intMuSet) // [3, 1, 2]

val muSet = muList.toMutableSet()
println(muSet) // [tim, andy, ann]

讀取 set - elementAt()

set 讀取就無法使用 muSet[0] 或 muSet.get(0)

要用 elementAt()

// set沒有這種寫法, 要用 elementAt, set 沒有 index 排序, 所以沒有[]
// muSet[0]
// muSet.get(0)
muSet.elementAt(0) // "tim"

elementAtOrElse() , elementAtOrNull()

跟昨天的 list 一樣,set 也有類似的操作

elementAtOrElse() 當取不到值時,會傳最後 lambda 內的值

elementAtOrNull() 當取不到值時,會回傳 null ,這裡還用了貓王運算子,所以會傳回 "no value"

muSet.elementAtOrElse(4) { "no value" }
muSet.elementAtOrNull(5) ?: "no value"

修改刪除 mutableSet

// 印出 set 大小
println(muSet.size)

// 在 set 最後面加入
muSet.add("Bob")

// 在 set 最後面加入一堆 data
muSet.addAll(listOf("a", "b", "c"))

// remove 某資料
muSet.remove("tim")
// 清除所有
muSet.clear()

HashSet - hashSetOf()

因為 hashSet 底層是 Java 的 HashSet,所以印出時並不會照加入順序印出,會是無序

val hashSet = hashSetOf("b", "a", "c")
println(hashSet) // [a, b, c]

LinkedHashSet - linkedSetOf()

其實這個跟 mutableSetOf() 一樣,因為底層都一樣是 LinkedHashSet

val linkedSet = linkedSetOf("b", "a", "c")
println(linkedSet) // [b, a, c]

TreeSet - sortedSetOf()

sortedSetOf() 底層是 Java 的 TreeSet,所以會依資料的自然排序做升序排序,以數字來說就是升序啦,所以也為什麼被取名叫 sortedSet

val sortedSet = sortedSetOf("1234", "12", "555555")
println(sortedSet) // [12, 1234, 555555]

emptySet<類型>()

一個空的 set,跟之前 emptyList<>() 用意差不多

emptySet<String>()

loop

loop 的部分也跟 list 差不多,只是 get() 要換成 elementAt()

// for
val sMuSet = mutableSetOf("e", "d", "c", "b")
println("for demo...")
for (data in sMuSet) { 
    println(data)
}

for (idx in sMuSet.indices) { 
    println(sMuSet.elementAt(idx))
}

for (d in sMuSet.withIndex()) {
    println("idx: ${d.index}, value: ${d.value}")
}

sMuSet.forEach {
    println("each name: $it")
}

sMuSet.forEachIndexed { index, name ->
    println("each name: #${index} - $name")
}

val 真的是唯讀嗎?

還記得一開始有提到 val 是唯讀的,要變動的值要宣告 var

但來看 list 或 set 的 mutable 的例子

宣告了 x 和 y 兩個 set,內容都一樣,此時 x == y 是 true

val x = mutableSetOf(4, 5, 6, 7)
val y = mutableSetOf(4, 5, 6, 7)
println("val immutable test before:" + (x == y)) // true

但如果我在 x 加了 8,此時 x == y 就會是 false了!

x.add(8)
println("val immutable test after:" + (x == y)) // false

所以其實 val 並不能一定保證我們的變數是唯讀的,至少在使用一些可變的 Collections 的時候無法做到。

List to MutableList 的例子

val listMu = listOf(1, 2, 3)
(listMu as MutableList)[1] = 100
listMu.toMutableList().removeAt(1)
println(listMu)

Set to MutableSet 的例子

val setMu = setOf(1, 2, 3)
(setMu as MutableSet).add(100)
setMu.toMutableSet().remove(100)
println(setMu)

Set to List, List to Set

println(listMu.toSet())
println(setMu.toList())

以上就是今天的內容!謝謝大家!

今日練習的程式在這: 請點我