【Kotlin備忘録】コレクション関数 map, filter, generateSequence

## 目的
* 自身への備忘録
* 書籍「[Kotlinプログラミング](https://www.shoeisha.co.jp/book/detail/9784798160191)」の復習

## 実行環境
* [Kotlin Playground](https://play.kotlinlang.org)
* Kotlin Version 1.4.10 <- 歯車マーク(Setting)からバージョンが確認できます

## Map
コレクションの各要素について、加工をした結果を`List`として取得します。

#### サンプルコード1
既存のコレクションで保持している各要素に対して、文字列を付与した新たなコレクションを取得します。

```kotlin
fun main() {

    val fruits = listOf("Strawberry", "Grape", "Orange")

    // fruits の各要素に文字列を追加したListを作成
    val greatFruits = fruits.map {
        "Great $it!" // <- 各要素は"it"として取得できる
    }

    println(fruits)
    println(greatFruits)
}
```
出力結果

```
[Strawberry, Grape, Orange]
[Great Strawberry!, Great Grape!, Great Orange!]
```

#### サンプルコード2
既存のMapのキーと値を入れ替えた新たなMapを作成する

```kotlin
fun main() {
    val pricesByFruit = mapOf("Strawberry" to 4.5, "Grape" to 5.1, "Orange" to 3.0)

    // 既存のMapのキーと値を入れ替えたMapを作成する
    val fruitByPrice = pricesByFruit.map {
        // pricesByFruitの各要素の値を利用したPairを作成し、Listの1要素として取得
        it.value to it.key
    }.toMap() // <- そのままだとListが戻り値になるため、toMap()でMapに変更する

    println(pricesByFruit)
    println(fruitByPrice)
}
```

出力結果

```
{Strawberry=4.5, Grape=5.1, Orange=3.0}
{4.5=Strawberry, 5.1=Grape, 3.0=Orange}
```

#### おまけ
サンプルコード2(Mapのキーと値を入れ替える処理)を関数として定義

```kotlin
/**
 * MapのキーとValueを入れ替えたMapを生成する
 * Genericsを利用して、どのような型でも入るようにしている
 * (K = MapKey, V = MapValue を意図している)
 * ※キーになる値が同一の場合、マージされるので注意すること　
 */
fun <K, V> flipValues(sourceMap: Map<K, V>) : Map<V, K> = sourceMap
    .map {
           it.value to it.key
        }
    .toMap()
```



## Filter
コレクションの各要素について、結果に合致する`List`を取得します。

#### サンプルコード
コレクションから `g` `G` が含まれている要素を抜き出す

```kotlin
fun main() {
    val fruits = listOf("Strawberry", "Grape", "Orange")

    val gFruits = fruits.filter {
        // 要素をすべて小文字にし、大文字小文字関係なく"g"が入っているかをチェック
        it.toLowerCase().contains("g") // <- 各要素は"it"として取得できる
    }

    println(fruits)
    println(gFruits)
}
```

出力結果

```
[Strawberry, Grape, Orange]
[Grape, Orange]
```

## コレクションの各要素取得方法について
コレクションの各要素を取得する方法としては、コレクションをループで回して、加工した各要素を変数に代入するという方法もあります。

mapのサンプルコードのループによる代入で書き換えたものが以下です。

```kotlin
fun main() {
    val fruits = listOf("Strawberry", "Grape", "Orange")

    // あらかじめ作成した変数にforEach内で要素を追加する
    val fGreatFruit = mutableListOf<String>()
    fruits.forEach{
        fGreatFruit.add("Great $it!")
    }

    println(fruits)
    println(fGreatFruit)
}
```

ループにて取得したコードも`map`で取得した場合と同じ出力結果が得られますが、以下の点が好ましくないと考えております。

* 代入先が`Mutable`になる <- 別箇所で変数を利用する際、予期せぬ代入が行われているかもしれない
* 変数の宣言と代入処理が分離するため、見通しが悪くなりやすい <- 宣言と代入処理が離れる場合がある

## おまけ（generateSequence）
複数のリストを組み合わせて1つのコレクションを作る際に、`generateSequence`が利用可能です。
おまけとしてサンプルコードを残します。

### 単純な組み合わせを扱うパターン

```kotlin
fun main() {
    val fruits = listOf("Strawberry", "Grape", "Orange", "Banana", "Apple")
    val adjectives  = listOf("Sour", "Chewy", "Sweet", "Hard", "Soft")

    // 形容詞と果物名を組み合わせた文字列でSequenceオブジェクトを作成する
    val fruitsStr = generateSequence{
        val fruit = fruits.random()
        val adjective = adjectives.random()
        "$adjective $fruit"
    }.take(15) // 15個の要素を取得
    
    fruitsStr.forEach{ println(it) }
}
```

出力結果（15個の形容詞付きフルーツ名が表示されている）

```
Chewy Strawberry
Sour Orange
Hard Orange
Chewy Apple
Sweet Grape
Hard Orange
Hard Apple
Hard Banana
Chewy Apple
Chewy Grape
Chewy Grape
Chewy Orange
Hard Strawberry
Chewy Banana
Soft Orange
```

上記のように複数のリストの内容を組み合わせた新たな`Sequence`オブジェクトが取得可能で、その中身をループを利用して取得することが可能です。
※`Chewy Grape`が2つ入っていることからも分かる通り、要素はユニークではありません

### ユニークな組み合わせを扱うパターン

```kotlin
fun main() {
    val fruits = listOf("Strawberry", "Grape", "Orange", "Banana", "Apple")
    val adjectives  = listOf("Sour", "Chewy", "Sweet", "Hard", "Soft")

    // 形容詞と果物名を組み合わせた文字列でSequenceオブジェクトを作成する
    val fruitsStr = generateSequence{
        val fruit = fruits.random()
        val adjective = adjectives.random()
        "$adjective $fruit"
    }.distinct().take(15) // distinct()で重複を排除し、そこから15個の要素を取得
    
    fruitsStr.forEach{ println(it) }
}
```
`distinct()`を追加することで、`sequence`内から重複要素を削除しています。

出力結果（15個の**ユニークな**形容詞付きフルーツ名が表示されている）

```
Hard Apple
Soft Grape
Sour Orange
Sweet Grape
Sour Apple
Chewy Orange
Chewy Grape
Soft Banana
Hard Strawberry
Hard Orange
Chewy Banana
Hard Banana
Soft Apple
Soft Orange
Sour Strawberry
```


## 参考にさせていただいたURI
#### Qiita
* [Kotlin のコレクション使い方メモ](https://qiita.com/opengl-8080/items/36351dca891b6d9c9687)
* [KotlinとMap](https://qiita.com/tasogarei/items/9c806da48c5b4c83f17e)
* [【Kotlin】Sequenceオブジェクト生成方法7種](https://qiita.com/sdkei/items/cc3d7846b09c87603718#fn1)

#### Kotlinlang.org
* [map](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/map.html)
* [filter](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/filter.html)
* [generateSequence](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/generate-sequence.html)