Kotlin KoansでKotlin入門　第２１回：Filter map

# はじめに
公式の問題集[「Kotlin Koans」](https://play.kotlinlang.org/koans/overview)を解きながらKotlinを学習します。

過去記事はこちら
- Introduction
  - [第０回：Kotlin Koansについて](https://qiita.com/kosuke1/items/41d192af63485bfc8cb8)
  - [第１回：Simple Functions](https://qiita.com/kosuke1/items/5862a3ece96082a62e67)
  - [第２回：Named arguments](https://qiita.com/kosuke1/items/2af11262852ee41b5da7)
  - [第３回：Default arguments](https://qiita.com/kosuke1/items/16cb8ac780df58dc8054)
  - [第４回：Triple-quoted strings](https://qiita.com/kosuke1/items/52cfeed2c49b0252d40e)
  - [第５回：String templates](https://qiita.com/kosuke1/items/0221bbbc5bc70847be6f)
  - [第６回：Nullable types](https://qiita.com/kosuke1/items/aa96e422c5313b6961bc)
  - [第７回：Nothing type](https://qiita.com/kosuke1/items/1ca0e48820d58c9dfe16)
  - [第８回：Lambdas](https://qiita.com/kosuke1/items/8de74f9491e003127f53)
- Classes
  - [第９回：Data classes](https://qiita.com/kosuke1/items/1be2de1b4406b8d914bf) 
  - [第１０回：Smart casts](https://qiita.com/kosuke1/items/50bdecaa0740eb0e1a17)
  - [第１１回：Sealed classes](https://qiita.com/kosuke1/items/71a4da02fe1e99da5d63)
  - [第１２回：Rename on import](https://qiita.com/kosuke1/items/f11465cc15a94e7589a3)
  - [第１３回：Extension functions](https://qiita.com/kosuke1/items/d4a1da00bc142c297221)
- Conventions
  - [第１４回：Comparison](https://qiita.com/kosuke1/items/e9486d044cae32167f36) 
  - [第１５回：Ranges](https://qiita.com/kosuke1/items/797f049ce5f33b1810c9)
  - [第１６回：For loop](https://qiita.com/kosuke1/items/f5f6eeea41fb89b2a20c)
  - [第１７回：Operators overloading](https://qiita.com/kosuke1/items/9845f98a632121f1493b)
  - [第１８回：Invoke](https://qiita.com/kosuke1/items/7879f83341d169374eb3)
- Collections
  - [第１９回：Collections Introduction](https://qiita.com/kosuke1/items/af91a0bd505cd93a3900) 
  - [第２０回：Sort](https://qiita.com/kosuke1/items/ed9a4b36f8573fc65a8f)


# 問題
[Filter map](https://play.kotlinlang.org/koans/Collections/Filter%20map/Task.kt)
map関数とfilter関数を使って、以下の拡張関数を実装してください。
- 顧客の出身地が異なるすべての都市を検索する
- 指定された都市に住んでいる顧客を検索する

```Kotlin
val numbers = listOf(1, -1, 2)
numbers.filter { it > 0 } == listOf(1, 2)
numbers.map { it * it } == listOf(1, 1, 4)
```



```修正前のコード.kt
// Find all the different cities the customers are from
fun Shop.getCustomerCities(): Set<City> =
        TODO()

// Find the customers living in a given city
fun Shop.getCustomersFrom(city: 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
}
```


# 問題のポイント
コレクションの[マッピング](https://kotlinlang.org/docs/collection-transformations.html#map)と[フィルタリング](https://kotlinlang.org/docs/collection-filtering.html#filter-by-predicate)について学びます。

## map
マッピング変換は、別のコレクションの要素に対する関数の結果からコレクションを作成します。
さらに要素のインデックスを引数として使う変換を行うには、 mapIndexed()を使用します。
```Kotlin
val numbers = setOf(1, 2, 3)
println(numbers.map { it * 3 }) // ==>[3, 6, 9]
println(numbers.mapIndexed { idx, value -> value * idx }) // ==>[0, 2, 6]
```
## Filter by predicate﻿
基本的なフィルタリング関数は、filter()です。述語を指定して呼び出すと、 filter()はそれにマッチするコレクション要素を返します。ListとSetの両方について、結果のコレクションはListになり、Mapについては同様にMapになります。
```Kotlin
val numbers = listOf("one", "two", "three", "four")  
val longerThan3 = numbers.filter { it.length > 3 }
println(longerThan3) // ==>[three, four]

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
val filteredMap = numbersMap.filter { (key, value) -> key.endsWith("1") && value > 10}
println(filteredMap) // ==>{key11=11}
```



# 解答例
```Kotlin
// 顧客の出身地が異なるすべての都市を検索する
fun Shop.getCustomerCities(): Set<City> = customers.map { it.city }.toSet()

// 指定された都市に住んでいる顧客を検索する
fun Shop.getCustomersFrom(city: City): List<Customer> = customers.filter { it.city == city }

```