在整理資料的時候,分組也是一個很常見的需求,比方說 Collection 裡有很多字串,你想要依照字首的字母做分類,這樣的需求 Kotlin 的標準函式庫也都準備好啦!在這個章節裡就要跟大家介紹這方面的功能。
Kotlin 標準函式庫裡有 groupBy()
method 可以用來做分組,我們需要傳入一個 Lambda 做分組條件,groupBy()
會回傳一個 Map
。這個 Map
的 key 會是這個 Lambda 的結果,而對應的 value 就會是原始 Collection 裡的被分組的元素。
val numbers = listOf("one", "two", "three", "four", "five")
numbers.groupBy { it.first().toUpperCase() }
// {O=[one], T=[two, three], F=[four, five]}
有時分組後,還會想要將裡面的元素轉型(Transform),與其要自己分兩步驟做,Kotlin 標準函式庫在設計 groupBy()
就想到這個需求了!所以 groupBy()
可以傳入 2 個 Lambda,第一個 Lambda 叫 keySelector
,意思就是用什麼當做 key 的分組條件;第二個 Lambda 叫 valueTransform
,意思就是要在 value 執行什麼轉換,兩個 Lambda 一併使用可以省下很多動作!
比方說剛剛上一個例子,我們除了用字首做分組外,還希望每一組裡面的字都可以字首大寫的話,我們可以這樣寫:
val numbers = listOf("oNe", "tWo", "tHRee", "foUR", "fIvE")
numbers.groupBy(
keySelector = { it.first() },
valueTransform = { it.toLowerCase().capitalize() }
)
// {O=[One], T=[Two, Three], F=[Four, Five]}
有時分組後,還會想要再對各組的 Collection 做二次操作,比方說計算各組裡面的數量,這時可以使用的是 groupingBy()
,它會回傳一個 Grouping
的類別,讓我們可以再套用如 eachCount()
、fold()
、reduce()
及 aggregate()
等操作。換句話說,這個二次操作有可能會再次改變回傳 Map 裡 value 的格式與內容,讓分組動作可以做的事情更多!
val numbers = listOf("one", "two", "three", "four", "five", "six")
numbers.groupingBy { it.first() }.eachCount() // {o=1, t=2, f=2, s=1}
關於 fold()
、reduce()
及 aggregate()
等轉型操作,我們會在後續的章節做更深入的討論。
在這個章節裡,我們討論了 Collection 的分組,跟其他操作的不同之處,就是回傳的類型是 Map
而不是 List
,這點要稍為注意一下。為了一覽這些 API 在不同 Collection 上的行為,以下用表格來整理本章所討論到的 method:
行為 | Array | List | Set | Map | |
---|---|---|---|---|---|
groupBy{} | 用 Lambda 分組 | v | v | v | x |
groupingBy{}} | 用 Lambda 分組後再操作 | v | v | v | x |