はじめに
公式の問題集「Kotlin Koans」を解きながらKotlinを学習します。
過去記事はこちら
- Introduction
- Classes
- Conventions
- Collections
問題
Group By
groupingについて学びます。
groupBy を使って関数を実装し、指定された都市に住む顧客を格納するマップを作成します。
val result =
listOf("a", "b", "ba", "ccc", "ad")
.groupBy { it.length }
result == mapOf(
1 to listOf("a", "b"),
2 to listOf("ba", "ad"),
3 to listOf("ccc"))
修正前コード.kt
// Build a map that stores the customers living in a given city
fun Shop.groupCustomersByCity(): Map<City, List<Customer>> =
TODO()
Shop.kt
data class Shop(val name: String, val customers: List<Customer>)
data class Customer(val name: String, val city: City, val orders: List<Order>) {
override fun toString() = "$name from ${city.name}"
}
data class Order(val products: List<Product>, val isDelivered: Boolean)
data class Product(val name: String, val price: Double) {
override fun toString() = "'$name' for $price"
}
data class City(val name: String) {
override fun toString() = name
}
問題のポイント
Kotlinの標準ライブラリには、コレクション要素をグループ化するための拡張関数が用意されています。
基本的な関数groupBy()は、ラムダ関数を受け取り、Mapを返しまる。
このMapでは、各キーがラムダ関数の結果で、対応する値はこの結果が返される要素のListです。
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.groupBy { it.first().uppercase() }) // {O=[one], T=[two, three], F=[four, five]}
また、groupBy()に第二引数としてラムダ関数を指定することもできます。
2つのラムダを指定したgroupBy()の結果マップでは、keySelector関数が生成するキーが、元の要素の代わりに値変換関数の結果にマップされます。
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.groupBy(keySelector = { it.first() }, valueTransform = { it.uppercase() })) // {o=[ONE], t=[TWO, THREE], f=[FOUR, FIVE]}
解答例
// Build a map that stores the customers living in a given city
fun Shop.groupCustomersByCity(): Map<City, List<Customer>> =
customers.groupBy { it.city }