Kotlin 的標準函式庫中提供了一些函式可以讓你取出部分的集合。
說明
Slice
slice 會回傳索引值的元素值。
val numbers = listOf("A", "B", "C", "D", "E", "F")
println(numbers.slice(1..3))
索引值會是從 0 開始,結果如下。
[B, C, D]
[one, three, five]
[four, six, one]
你也可以照下面這樣做。
val numbers = listOf("A", "B", "C", "D", "E", "F")
println(numbers.slice(0..4 step 2))
println(numbers.slice(setOf(3, 5, 0)))
Take and drop
take 顧名思義就是取得某個 index 的元素,因此,你可以使用 take(第n個元素) 來取得該元素值,下面就是取得集合內的第一個元素值。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.take(1))
所以得到結果如下。
[1]
你也可以從後面開始數,使用 takeLast(取多少個元素),就是從後面數過來要取幾個元素值。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.takeLast(numbers.size))
這樣的結果就會變成如下。
[1, 2, 3, 4, 5, 6]
還是不了解?那取 2 個元素試看看。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.takeLast(2))
結果就會如下。
[5, 6]
drop 跟 take 使用方法類似,只是反過來是把某些元素去掉。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.drop(1))
這樣結果就會變成去掉第一個元素的集合。
[2, 3, 4, 5, 6]
如果反過來使用 dropLast,就是代表從後面數過來刪除掉第一個元素。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.dropLast(1))
那麼結果就會最後一個元素被刪除。
[1, 2, 3, 4, 5]
如果你要從前面開始數就可以使用 takeWhile 並且在 lambda 內設定條件。
可以點進去看原始碼說明。
Returns a list containing first elements satisfying the given [predicate].
從第一個符合條件的元素開始回傳往後的集合。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.takeWhile { it < 4 })
所以從前面數過來,取得元素直到 4 < 4 不成立,所以回傳前面 [1, 2, 3],結果如下。
[1, 2, 3]
那如果第一個元素不符合,他就會回傳一個空字串。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.takeWhile { it > 4 })
結果如下。
[]
如上面的反過來設定條件,就可以使用 takeLastWhile 並且給定 lambda 一個條件值,直到條件滿足為止。
文件說明如下。
Returns a list containing last elements satisfying the given [predicate].
從最後一個元素符合條件之集合。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.takeLastWhile { it < 4 })
因為從後面開始數,第一個結果不符合,就會返回空集合,結果就會如下。
[]
改成第一個條件符合。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.takeLastWhile { it == 6 })
結果就會變成只有最後一個元素符合,結果如下。
[6]
當然一樣有 dropWhile 跟 dropLastWhile。
dropWhile 從文件上的描述上可以得知。
Returns a list containing all elements except first elements that satisfy the given [predicate].
從前面第一個元素比對是否符合 lambda 內的條件,不符合的就湊成集合回傳。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.dropWhile { it == 1 })
第一個元素會符合所以刪除掉,然後剩下的會回傳,結果如下。
[2, 3, 4, 5, 6]
跟 takeWhile 與 takeLastWhile 相反是 不符合
回傳,因此,如果你第一個條件不符合就會加入回傳集合內。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.dropWhile { it > 1 })
結果如下。
[1, 2, 3, 4, 5, 6]
dropLastWhile 則是從集合後方開始數。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.dropLastWhile { it == 6 })
結果如下。
[1, 2, 3, 4, 5]
Chunked
chunked 分塊是一種常見的操作,集合中的 chunked() 方法可以幫你把集合切成對應的區塊,根據設定的區塊的大小來區分,直到切滿或者沒切滿形成一個區塊。
val list = (0..12).toList()
println(list.chunked(3))
區分成三部分,最後一步的部分湊不成三塊,因此,就把剩下的一部分弄成一塊,結果如下。
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12]]
你也可以對分塊後的區塊內進行一些條件設定,比如說將所有的元素進行加總。
val numbers = (0..12).toList()
println(numbers.chunked(3) { it.sum() })
結果如下。
[3, 12, 21, 30, 12]
Windowed
windowed 可以解釋成滑動窗口,意思有點像是在某個框框內框起來的集合內,所看到的範圍。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.windowed(3))
這樣一來就會看到限制 3 個元素的框框,每次平移 1 個元素,因此結果會變成下面結果。
[[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]
你就會好奇是否可以選擇要平移的步數,當然是可以的。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.windowed(3, step = 2, partialWindows = false))
每次平移 2 個單位,所以預期會是 [1, 2, 3] 接著是 [3, 4, 5],那後面沒有辦法移動了怎麼辦?這個就是 partialWindows 這個參數的功能,選擇要不要繼續移動下去,結果如下。
[[1, 2, 3], [3, 4, 5]]
如果我們改成 true 看看。
val numbers = listOf(1, 2, 3, 4, 5, 6)
println(numbers.windowed(3, step = 2, partialWindows = true))
結果就是硬擠。
[[1, 2, 3], [3, 4, 5], [5, 6]]