はじめに
公式の問題集「Kotlin Koans」を解きながらKotlinを学習します。
過去記事はこちら
- Introduction
- Classes
- Conventions
- Collections
問題
フラット化について学び、flatMap を使って 2 つの関数を実装します。
- 最初の関数は、与えられた顧客が注文したすべての製品を返す
- 2つ目は、少なくとも1人の顧客が注文したすべての製品を返す
val result = listOf("abc", "12").flatMap { it.toList() }
result == listOf('a', 'b', 'c', '1', '2')
修正前コード.kt
// Return all products the given customer has ordered
fun Customer.getOrderedProducts(): List<Product> =
TODO()
// Return all products that were ordered by at least one customer
fun Shop.getOrderedProducts(): Set<Product> =
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
}
問題のポイント
ネストされたコレクションを操作する場合、ネストされたコレクション要素にフラットにアクセスできる標準ライブラリ関数が便利です。
最初の関数はflatten()です。この関数は、コレクションのコレクション、例えばセットのリストに対して呼び出すことができます。この関数は、ネストされたコレクションのすべての要素からなる単一のリストを返します。
val numberSets = listOf(setOf(1, 2, 3), setOf(4, 5, 6), setOf(1, 2))
println(numberSets.flatten()) // [1, 2, 3, 4, 5, 6, 1, 2]
もうひとつの関数 flatMap() は、入れ子になったコレクションを柔軟に処理する方法を提供します。
これは、コレクションの要素を別のコレクションにマップする関数を受け取ります。
その結果、flatMap() はすべての要素について、その戻り値の単一のリストを返します。
つまり、flatMap() は map() (マッピング結果としてコレクションを持つ) と flatten() を続けて呼び出したものとして振る舞います。
val containers = listOf(
StringContainer(listOf("one", "two", "three")),
StringContainer(listOf("four", "five", "six")),
StringContainer(listOf("seven", "eight"))
)
println(containers.flatMap { it.values }) // [one, two, three, four, five, six, seven, eight]
解答例
// Return all products the given customer has ordered
fun Customer.getOrderedProducts(): List<Product> =
orders.flatMap(Order::products)
// Return all products that were ordered by at least one customer
fun Shop.getOrderedProducts(): Set<Product> =
customers.flatMap(Customer::getOrderedProducts).toSet()