はじめに
公式の問題集「Kotlin Koans」を解きながらKotlinを学習します。
過去記事はこちら
- Introduction
- Classes
- Conventions
- Collections
問題
Aggregate operationsについて学びます。
2つの関数を実装します。
- 最初の関数は、ショップで最も多くの注文を出した顧客を返すこと。
- 2つ目は、指定された顧客が注文した中で最も高価な商品を返すことです。
関数maxOrNull、minOrNull、maxByOrNull、minByOrNullが役に立つかもしれません。
listOf(1, 42, 4).maxOrNull() == 42
listOf("a", "ab").minByOrNull(String::length) == "a"
ラムダ式の代わりにcallable references(呼び出し可能な参照)を使用することができます。特に、異なるラムダで発生し、異なる型を持つコールチェーンで役に立ちます。getMostExpensiveProductBy関数をcallable referencesを使用して実装します。
修正前コード.kt
// ショップで最も多くの注文を出した顧客を返す
fun Shop.getCustomerWithMaxOrders(): Customer? =
TODO()
// 指定された顧客が注文した中で最も高価な商品を返す
fun getMostExpensiveProductBy(customer: Customer): 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
}
問題のポイント
minOrNull() と maxOrNull() はそれぞれ最小の要素と最大の要素を返します。
空のコレクションでは、これらはnullを返します。
fun main() {
val numbers = listOf(6, 42, 10, 4)
println("Count: ${numbers.count()}") // Count: 4
println("Max: ${numbers.maxOrNull()}") // Max: 42
println("Min: ${numbers.minOrNull()}") // Min: 4
println("Average: ${numbers.average()}") // Average: 15.5
println("Sum: ${numbers.sum()}") // Sum: 62
}
また、特定のセレクタ関数やカスタムComparatorによって、最小・最大の要素を取得する機能もあります。
- maxByOrNull()とminByOrNull()はセレクタ関数を受け取り、その関数が最大または最小の値を返す要素を返します。
- maxWithOrNull()およびminWithOrNull()はComparatorオブジェクトを取り、そのComparatorに従って最大または最小の要素を返します。
- maxOfOrNull()、minOfOrNull()はセレクタ関数を受け取り、そのセレクタ自体の最大または最小の戻り値を返します。
- maxOfWithOrNull() および minOfWithOrNull() は Comparator オブジェクトを取り、その Comparator に従って最大または最小のセレクタの戻り値を返します。
val numbers = listOf(5, 42, 10, 4)
val min3Remainder = numbers.minByOrNull { it % 3 }
println(min3Remainder) // 42
解答例
// ショップで最も多くの注文を出した顧客を返す
fun Shop.getCustomerWithMaxOrders(): Customer? =
customers.maxByOrNull { it.orders.size }
// 指定された顧客が注文した中で最も高価な商品を返す
fun getMostExpensiveProductBy(customer: Customer): Product? =
customer.orders.flatMap(Order::products).maxByOrNull(Product::price)