map, reduceなどをマスターしたい

# はじめに

swiftはかなり楽しい言語です。私はとても気に入っています。クロージャにも慣れました。ですが、どうにも不慣れな関数群があります。高階関数とか呼ばれるあれ、例えば、`map`です。
人様のコードをみていると、私だったら`for`文で書くところを、`map`を使ってさらっと一行で書いていたりしていて、すごくかっこいい。単純に憧れます。

私も使えるようになりたい。

というわけで、理解するために自分用に噛み砕いたメモを作ってみます。(swift5で動作確認しながら作成)

# `map`

簡単な例として、あるタプルの配列から一部だけを抜き出した配列を作成する事を考えます。
素直に`for`文で書くとこうです。

```swift
let list = [("Tokyo", 22), ("London", 18)]
var cityList:[String] = []
for (city, _) in list {
    cityList.append(city)
} 
// cityList == ["Tokyo", "London"]
```

これが、`map`を使うとこうなります。

```swift
let list = [("Tokyo", 22), ("London", 18)]
let cityList = list.map { $0.0 }  // ["Tokyo", "London"]
```

おお。かっこいい。スッキリしています。
ですが、私には、`cityList`が`String`の配列になることが直感的に見えてきません。よくわからないけど、コメントを信じて次へ進むことしかできません。

理解するために、なぜこうなるのかを紐解いてみます

### `map`の定義
上述の`map`関数は、`Array`構造体のメソッドです。定義は以下の通り。
(実際には`throws`や`rethrows`などのエラー制御用のキーワードがありますがここでは省略します)

```swift
func map<T>(_ transform: (Element) -> T) -> [T]
```

この定義から、`map`メソッドは、`(Element) -> T`型の関数(クロージャ)をひとつ受け取って、`T`の配列を返すメソッドであるとわかりました。結構シンプルな形をしています。
関数の説明によれば、このクロージャは**マッピングクロージャ**と呼ばれています。(数学ではmapは写像という意味のようです)
なお、`T`は任意の型を意味します。（ご存知ない方は後述のジェネリクスを参照してください。）実際に使うときに、型を決めて使います。Tの部分がみな同じ型になる、という点だけ押さえればよいです。
`Element`は元の配列の中身であって、型はIntの配列ならInt、Stringの配列ならStringになります。今回の例はタプルの配列なので、`Element`はタプルです。

配列の`map`メソッドは、その配列の項目を一つずつ、このマッピングクロージャに渡して実行します。クロージャの戻り値を順に配列に入れて、最終的にその戻り値の配列を、`map`メソッドの結果として返してきます。つまりマッピングメソッドの出力を配列にしてくれます。

なんだか'map'が単純な関数に思えてきました。今回はタプルの配列から文字列部分だけを抜き出したいので、マッピングメソッドで受け取ったタプルの文字列部分を返すようにすれば、文字列の配列が得られることになります。目的にぴったりな便利関数です。

この理解から、最初の`for`ループの処理を`map`に置き換えてみます。

```swift
let list = [("Tokyo", 22), ("London", 18)]
let cityList = list.map({ (city: String, _: Int) -> String in
    return city
 })  // ["Tokyo", "London"]
```

クロージャで配列の要素をうけとって、その中の欲しい情報を戻り値にすれば、その配列が出来上がる、というわけです。なるほど、簡単です。
しかし、見た目は別にわかりやすくないし、シンプルでもありません。かっこよくもない。これだったら、まだ`for`文の方が、わかりやすくて断然マシだと思えます。

ここから、swiftの仕様を使って、強引にシンプルな見た目に近づけていきます。

### クロージャの定義を引数のカッコの後ろに出す
swiftでは、関数の最後の引数がクロージャの場合、引数定義の()の後ろに出して書くことができる、というルールがあります。**Tailing closure** と呼ばれる書き方で、`UIView.animate`などでおなじみ(?)です。

```swift
// これを
UIView.animate(withDuration: 0.3, animation: {
    self.aView.alpha = 1
})
// こう書いてもよい。
UIView.animate(withDucation: 0.3) {
    self.aView.alpha = 1
}
```

これを使って書き直します。

```swift
let list = [("Tokyo", 22), ("London", 18)]
let cityList = list.map() { (city: String, _: Int) -> String in
    return city
 }  // ["Tokyo", "London"]
```

そして、`map`の次の`()`も(他の引数がないので)省略できてしまいます。

```swift
let list = [("Tokyo", 22), ("London", 18)]
let cityList = list.map { (city: String, _: Int) -> String in
    return city
 }  // ["Tokyo", "London"]
```

なんだか見た目が`for`文みたいになりましたが、制御構文ではなくて、あくまでも`map`メソッドに`{}`内のクロージャを渡しているだけです。
なお、`()`を省略できるのは、関数の引数がクロージャ一つだけで、Tailing Closureを使う場合に限られます。関数呼び出し`hoge()`を`hoge`と書いてもいい、というわけではありません。なかなか強引な仕様です。

### 引数を一つにする
ここまではタプルを展開した状態で受け取っていましたが、元々、マッピングクロージャは、配列の要素を一つだけ受け取るという定義でしたね。この後の説明と整合しなくなるので、ここで、ひとつのタプルとして扱うように直しておきます。

```swift
let list = [("Tokyo", 22), ("London", 18)]
let cityList = list.map { (element:(String,Int)) -> String in
    return element.0
 }  // ["Tokyo", "London"]
```

ここで登場した`.0`は、タプルの0番目の項目という意味です。ご存知ない方は、タプルを調べてみてください。

### クロージャ定義の型を省略
`{`と`in`の間に`map`メソッドのクロージャの型定義がありますが、なんとこれらは省略可能です。
クロージャが受け取る引数の型は、`map`メソッドの定義で配列の要素と同じと決まっているので、わざわざ書かなくても自動的に決まります。しかし、クロージャが返す`T`は任意の型という定義でした。これを省略したら、コンパイルエラーになりそうです。

```swift
let list = [("Tokyo", 22), ("London", 18)]
let newList = list.map { (element) in
    return element.0
 }  // ["Tokyo", "London"]
```

実は、swiftはクロージャの戻り値の型から`T`を決める、という、賢い類推機能をもっています。`element.0`がString型なので、`map`はString型の配列を返します。returnの値を`element.1`にしたら、Int型の配列が`map`の出力になります。

おお、なるほどこれは簡単、便利で理にかなっているように思えます。

### クロージャの引数名定義を省略
残っているのは`element`というクロージャ内で引数を参照するための変数名定義だけとなりました。そして、これも省略できます。
swiftでは、クロージャの引数について、`$0`という暗黙の引数名を用いることができます。

```swift
let list = [("Tokyo", 22), ("London", 18)]
let newList = list.map { return $0.0 }  // ["Tokyo", "London"]
```

`$0`は **shorthand argument name** というもので、引数が複数あるときは、`$1`,`$2`,...というふうになります。また、`element`を囲っていた`()`も、`in`も不要です。

### `return` を省略
最後に残った`return`ですが、これさえも省略してしまいます。
swiftには、クロージャの中身が一文の場合は、returnを省略できる、という、またまた強引なルールがあります。**Inpricit returns from Single-Expression Closure**と、仕様書で説明されています。このとき、`return`がなくてもその一文の値を自動的に戻り値とする、という実に強引な仕様になっています。

```swift
let list = [("Tokyo", 22), ("London", 18)]
let newList = list.map { $0.0 }  // ["Tokyo", "London"]
```

やっと、最初の表現にたどり着きました。

単純な表記の裏に、推定や暗黙の決まりがたくさんあります。
これだけの変換や省略を頭の中で組み立てて、さらっとコーディングできる皆さんは、なかなか大したものだと思います。
私には、やっぱり書くのは難しいですが、読む事はできるような気がしてきました。

### `map`を読解するポイント
コードに現れる`map`を読むときに意識するべきポイントをまとめます。

+ マッピングクロージャには元の配列の値の一つが与えられる。`$0`でそれを参照すして使う。
+ クロージャの実体である一文は、クロージャの戻り値になる。 
+ クロージャの戻り値が配列に集められて`map`の結果になる。

# `reduce`
`Array`の`reduce`メソッドは以下の定義です。

```swift
func reduce<Result>(into initialResult: Result, _ updateAccumulatingResult: (inout Result, Element) throws -> ()) rethrows -> Result
```

reduceは`updateAccumelatingResult`の部分にクロージャを渡して、最終的にはResult型の値を一つだけ返します。
initialResultはResult型の初期値です。
クロージャには、Result型の値と、配列の要素の二つが渡され、戻り値はResult型です。
クロージャが受け取るResult型の値は、その前に呼び出されたクロージャの戻り値です。
一番最初のクロージャは、`reduce`に与えた`initialResult`の値と、一番最初の配列要素を受け取ります。それが返したResult型の値が、二番目の配列要素と一緒に次のクロージャ呼び出しに使われ、これを最後の要素まで繰り返します。
最後のクロージャが返した値が、`reduce`の結果になります。

順番に実行して結果を伝搬していく処理に向いていますね。全部足すとか。
以下の例はIntの配列を文字列に変換しています。

```swift
let list = [1, 2, 3, 4, 5]
let string = list.reduce ("") { $0 + "\($1), " }
// string = "1, 2, 3, 4, 5, "
```

`reduce`の最初の引数は初期値です。最初の引数があるので`map`みたいに()を省略することはできません。
`$0`は初期値または前のクロージャの戻り値で、ここではString型です。
$1は配列の値なので、Int型です。この型の違いが、reduceのポイントかなと思いました。

三項演算子を使って、気持ちの悪いケツカンマを外して[]で囲んでみます。

```swift
let list = [1, 2, 3, 4, 5]
let string = list.reduce ("") { $0 == "" ? "[\($1)" : $0 + ", \($1)" } + "]"
// string = "[1, 2, 3, 4, 5]"
```

一行ですが、トリッキーで読みやすいとは言えないと思います。
書くときは分かっているから楽しいですが、あとで読むときには辛いですね。

### reduce読解のポイント

+ `reduce`の第一引数が初期値で、次がクロージャ。
+ クロージャが受け取るのは、初期値または前のクロージャの戻り値、と、配列の値の二つ。
+ `$0`で初期値またはクロージャの戻り値を参照し、`$1`で配列の値を参照する。それぞれ型が違う場合がある。
+ 最後のクロージャの出力が、reduceの出力になる。

# `flatMap`

`Array`の`flatMap`の定義はこちら。

```swift
func flatMap<SegmentOfResult>(_ transform: (Element) -> SegmentOfResult) -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
```

これはなかなかややこしい。
`flatMap`は、クロージャを一つ受け取って、配列を返します。
クロージャは、配列の内容を一つずつ受け取って、SegmentOfResult型の値を返します。SegmentOfResult型は、`Sequence`プロトコルに準拠していなければならない。`[SegmentOfResult.Element]` という表記が私には謎ですが・・・

`map`はクロージャの戻り値を単に配列化して返すので、クロージャで配列を返すと二次元配列になってしまうのに対して、`flatMap`はクロージャの戻り値が一つの配列にフラットに展開されます。

```swift
let list = [("Tokyo", 22), ("London", 18)]
let map = list.map { Array($0.0) }
// map = [["T", "o", "k", "y", "o"], ["L", "o", "n", "d", "o", "n"]]
let flat = list.flatMap { Array($0.0) }
// flat = ["T", "o", "k", "y", "o", "L", "o", "n", "d", "o", "n"]
```

### `flatMap`の読解のポイント
+ `map`と同じ。
+ `map`の出力を二次元にしたくない場合に使う(みたい)


# `compactMap`

```swift
func compactMap<ElementOfResult>(_ transform: (Element) -> ElementOfResult?) -> [ElementOfResult]
```

`compactMap`は、`map`のマッピングクロージャがnilを返す場合であって、最終結果の配列にnilを入れたくないときに使う、と説明されています。
クロージャがnilを返したらそれを出力に含めない`map`です。なんだ、簡単。

# `sorted`

```swift
func sorted(by areInIncreasingOrder: (Element, Element) -> Bool) -> [Element]
```

勢いで`sorted`もやってみます。
`sorted`はクロージャを受け取って、新しい配列を返します。
要素二つをもらって、大小をBoolで返してあげたら、その順に並べ替えられた新しい配列ができます。

```swift
let list = [1, 3, 2, 5, 4]
let sortedList = list.sorted { $0 > 01 }
// sortedList = [5, 4, 3, 2, 1]
```

これは、

```swift
let list = [1, 3, 2, 5, 4]
let sortedList = list.sorted { (left:Int, right:Int) -> Bool in
    return left > right
}// sortedList = [5, 4, 3, 2, 1]
```

こういう意味ですね。

だいぶ読めるようになりました。

# 終わり
`Array`だけでなく、`Dictionary`も`map`などの便利関数群がたくさん用意されています。だいぶわかるようになった気がするので、これを機にいろいろ使ってみようと思います。
高階関数とか、カリー化とか、関数型言語とか、もともと`map`や`reduce`などが登場した背景技術には奥深いものがあるようです。考え方が根本からひっくり返るのがソフトウェアの醍醐味ですが、ここにもそれがありそうです。関数型言語はやったことがないので、機会を作って、是非勉強してみたいなと思います。

### ジェネリクス(Generics)
ジェネリクスは具体的な型を決めないで、クラスや構造体を定義するための仕組みです。例えば`Array`はジェネリクスを使って型に依存しない構造体として定義されています。Intの配列でもStringの配列でも、配列そのものに対する処理は共通であり、それらを型によらずに定義できるようにした技術です。

```swift
struct Array<Element>
```

`<`と`>`に挟んだElementが型名のかわりで、何かの型という意味です。慣習で`<T>`と`T`を使うことが多いと思うけれど、Swiftのドキュメントでは`Element`や`SegmentOfResult`などの意味を表す単語も使っています。
ジェネリクスによって、IntのArrayもStringのArrayもまとめて定義でき、同じように使えます。自分の作ったクラスでも使える。ジェネリクスが登場する前は、Arrayクラスを継承で任意の型に派生させたり、プロトコルやインターフェースを使ったりして、全部の型のために定義をわざわざ書いていました。

### もうひとつの`reduce`
`Array`の`reduce`にはもう一つのパターンがあります。

```swift
func reduce<Result>(into initialResult: Result, _ updateAccumulatingResult: (inout Result, Element) -> ()) -> Result
```

`reduce`の最初の引数の引数名が`initialResult`から、`into`に変わっています。そして、クロージャの1番目の引数に`inout`属性が付きました。
この`reduce`は、初期値を使いまわして結果まで再利用できるようです。

そういえば、この関数の説明の例題に、変な構文がでてきます。

```swift
let letters = "abracadabra"
let letterCount = letters.reduce(into: [:]) { counts, letter in
    counts[letter, default: 0] += 1
}
// letterCount == ["a": 5, "b": 2, "r": 2, "c": 1, "d": 1]
```
`[letter, default: 0]`と、辞書のキーを書くべきところに`,default: 0`という見慣れない書き方が・・・
調べてみたら、Qiitaに説明がありました。ありがとうございます。

[Swift4.0でDictionaryが大幅にパワーアップした](https://qiita.com/hanawat/items/341a6f7843f4e19780b5#subscript_default)

確かに、この構文があれば`+=`で簡単に書けますね。使ってみよう。