Swiftらしいコーディングを学ぶ 「コレクションに用いる高階関数とClosure」

# はじめに
前回[Swiftらしいコーディングを学ぶ 「CollectionType」](http://qiita.com/shoheiyokoyama/items/429a7aeef5836e764bb8)で配列や辞書型の基礎についてまとめましたが今回は主にコレクションで扱われる高階関数や`Closure`についてまとめていきたいと思います。

以下、本記事でまとめた内容です。

- <a href="#map">`map()`について</a>
- <a href="#for_each">`forEach()`について</a>
- <a href="#filter">`filter()`について</a>
- <a href="#reduce">`reduce()`について</a>
- <a href="#flat_map">`flatMap()`について</a>
- <a href="#closure">Closureについて</a>


# 高階関数
> 高階関数（こうかいかんすう、英: higher-order function）とは、関数（手続き）を引数にしたり、あるいは関数（手続き）を戻り値とするような関数のことである。
[wikipedia参照](https://ja.wikipedia.org/wiki/%E9%AB%98%E9%9A%8E%E9%96%A2%E6%95%B0)

Wikipediaの定義でもあるように、関数を引数に与えることができたり、関数を戻り値にできる関数のことを**高階関数**と言います。
主に関数型言語やラムダ計算において多用される関数で、SwiftのFunctionalな書き方を理解するためには学んでおきたい関数ですね。

Objcではなかった`map`, `filter`, `reduce`などが高階関数にあたり、コレクションの処理などで多様されています。今回は主にこれらの関数について学んでいきたいと思います。

# <a id="map">`map()`</a>

```swift:Collection.swift
@warn_unused_result
    public func map<T>(@noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]
```
[CollectionType](https://github.com/apple/swift/blob/master/stdlib/public/core/Collection.swift)に`map()`の定義があります。

- `@warn_unused_result` : 返り値がないとwarningを出す
- `@noescape` : 非同期処理ができず、保持できない。`Closure`の外の変数に`self`をつけずにアクセスできる

なお、`Closure`で処理されたコレクションが返るのは以下のイメージです。

```math
[x_1, x_2, .., x_n].map(f) = [f(x_1), f(x_2), .., f(n)] 
```

## 利用場面
`map()`はコレクションの全要素に処理を施し、`@warn_unused_result`が定義されているように処理を施されたコレクションを取得したい場合に利用します。


## 基本的な使い方

例えばObjcぽく書くとこんな感じのコードになりますね。

```swift
let array = [10.0, 20.0, 30.0]
var doubleArray = [Double]()
for value in array {
    doubleArray.append(value * 2.0)
}
print(doubleArray)
//[20.0, 40.0, 60.0]
```

これを`map()`を使うと以下のように書けます。

```swift
let array = [10.0, 20.0, 30.0]
var doubleArray = array.map {value in value * 2.0}
print(doubleArray)
//[20.0, 40.0, 60.0]

//このようにも書ける
//$0は最初の引数を意味している
var doubleArray = array.map {$0 * 2.0}
//[20.0, 40.0, 60.0]
```

上記の処理はFor-inLoopと比較するとわかりやすいかと思います。Closureの書き方や詳細は<a href="#closure">後述</a>
<p align="center"><img width="350" alt="スクリーンショット 2016-04-24 22.24.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/62451/f937b28f-aab5-1a18-6041-8e3495cff2f2.png"></p>

`Dictionary`を扱う場合は以下のようになります。

```swift
let dictionary = ["SWIFT": 2.1, "XCODE": 7.2].map { key, value in
    (key.lowercaseString, value + 0.1)
}
//[("swift", 2.2), ("xcode", 7.3)]

//引数を省略した場合
let dictionary = ["SWIFT": 2.1, "XCODE": 7.2].map { ($0.0.lowercaseString, $0.1 + 0.1) }
//[("swift", 2.2), ("xcode", 7.3)]
```

# <a id="for_each">`forEach()`</a>

```swift:Sequence.swift
public func forEach(@noescape body: (Self.Generator.Element) throws -> Void) rethrows
```
`forEach`は[SequenceType](https://github.com/apple/swift/blob/master/stdlib/public/core/Sequence.swift)に定義されています。内部で`For-in Loop`を扱っていますね。

`forEach`は`For-in Loop`とは明確な違いがあります。

- `break`や`continue`が使えない
- ループをスキップする場合は`return`を用いる

## 利用場面
`For-in Loop`と似てますが、単純なループ処理で扱うことが多いようです。全要素に処理を施されたコレクションを取得する場合は`map()`取得しない場合は`forEach`を利用するという感じですね。**全要素に処理を施さず、特定の条件でloopから抜けたい場合**は、`For-in Loop`を使ったほうがよさそうです。

## 基本的な使い方

以下の例は0を除く偶数の値を出力しています。

```swift
//Array
[0, 1, 2, 3, 4, 5, 6,].forEach { value in
    if value == 0 { return }
    
    if value % 2 == 0 {
        print("\(value) is even value")
    }
}
//"2 is even value"
//"4 is even value"
//"6 is even value"

```
Dictionaryの例です。キーが`Swift`の時の`Value`を出力しています。

```swift
//Dictionary
["Swift": 2.2, "Xcode": 7.3].forEach { key, value in
    if key == "Swift" {
        print("Swift version is \(value)")
    }
}
//"Swift version is 2.2"

//引数省略
["Swift": 2.2, "Xcode": 7.3].forEach { if $0.0 == "Swift" { print("Swift version is \($0.1)") } }
//"Swift version is 2.2"
```

# <a id="filter">`filter()`</a>
```swift:Sequence.swift
@warn_unused_result
    public func filter(@noescape includeElement: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.Generator.Element]
```
`filter()`は[SequenceType](https://github.com/apple/swift/blob/master/stdlib/public/core/Sequence.swift)に定義されています。`@warn_unused_result`があるように返り値を返す仕様になっていますね。なお、返されるコレクションは**要素がソートされて**返されます。

## 利用場面
コレクションの全要素に処理を施し、条件にマッチする要素のみを返すので、特定の要素のコレクションを取得したい場合に利用します。

## 基本的な使い方

値が偶数かつ8以下の数字の配列を取得しています。

```swift
let filteredArray = [0, 5, 4, 3, 2, 1, 6, 7, 9, 8, 10].filter { value in
    value % 2 == 0 && value < 8
}
//数字が昇順になって返される
//[0, 2, 4, 6]
```

バージョンが2.2以上の要素だけ取得しています

```swift
let filteredDictionary = ["NewVersion": 3.0, "CurrentVersion": 2.2, "OldVersion": 1.0].filter { key, version in
    version >= 2.2
}
//Keyの昇順になっている
//["CurrentVersion": 2.2, "NewVersion": 3.0]

//引数省略
let filteredDictionary = ["NewVersion": 3.0, "CurrentVersion": 2.2, "OldVersion": 1.0].filter { $0.1 >= 2.2 }
//["CurrentVersion": 2.2, "NewVersion": 3.0]

```

# <a id="reduce">`reduce()`</a>

```swift:Sequence.swift
@warn_unused_result
    public func reduce<T>(initial: T, @noescape combine: (T, Self.Generator.Element) throws -> T) rethrows -> T
```
`reduce()`は[SequenceType](https://github.com/apple/swift/blob/master/stdlib/public/core/Sequence.swift)に定義されています。これも返り値が必要となっていますね。第一引数には初期値を入れます。


## 利用場面

コレクションの要素を全て足しあわせたり、文字の要素を一つに連結させたい場合など、要素を集計したり、返り値に要素を一つにまとめたいときなどに利用します。


## 基本的な使い方
例として自分の点数を結果として結合した文字列を作成していきます。

```swift
var result = "Math: {}, Science: {}, English: {}"
let score = [65, 78, 96]
let myResult = score.reduce(result) { result, score in
    guard let range = result.rangeOfString("{}") else { return result }
    
    return result.stringByReplacingCharactersInRange(range, withString: String(score))
}
print(myResult)
//"Math: 65, Science: 78, English: 96"

//引数省略
let myResult = score.reduce(result) {
    guard let range = $0.rangeOfString("{}") else { return $0 }
    return $0.stringByReplacingCharactersInRange(range, withString: String($1))
}
print(myResult)
//"Math: 65, Science: 78, English: 96"
```

なお、二つの引数を取る場合は以下のような書き方もできます

```swift
let sum = [1, 2, 3, 4, 5].reduce(0, combine: +)
//15
let minusSum = [1, 2, 3, 4, 5].reduce(0, combine: -)
//-15
let multipliedSum = [1, 2, 3, 4, 5].reduce(1, combine: *)
//120

[1, 2, 3, 4, 5].reduce(0, combine: max)
//5
[1, 2, 3, 4, 5].reduce(1, combine: min)
//1
```

普段演算子として使用している`+`, `-`, `*`ですが、これらも[IntegerArithmetic](https://github.com/apple/swift/blob/master/stdlib/public/core/IntegerArithmetic.swift.gyb)で定義されている関数なのでこう言う書き方ができるんですね。



# <a id="flat_map">`flatMap()`</a>

```swift:SequenceAlgorithms.swift
@warn_unused_result
    public func flatMap<T>(@noescape transform: (Self.Generator.Element) throws -> T?) rethrows -> [T]
```

[SequenceAlgorithms.swift](https://github.com/apple/swift/blob/master/stdlib/public/core/SequenceAlgorithms.swift.gyb)に定義されています。クラスをよく見ると、

> Returns an `Array` containing the non-nil results of mapping

また、このような記述もあります。
> Use this method to receive a single-level collection when your transformation produces a sequence or collection for each element.


とあるように`flatMap()`は1次元のコレクションにして返してくれたり、nilを含まない値を返すようですね。

## 利用場面
上記で記載したように、`flatMap()`は二つの役割を持っています。

1. 1次元構造のコレクションを返す
2. 要素をアンラップしたコレクションを返す

よって、flatな構造のコレクションを取得したいとき、アンラップされた要素を取得したい場合などに利用します。アンラップしたコレクションを返してくれるので個人的には`map()`より`flatMap()`を積極的に使っていくべきかなと思います。

## 基本的な使い方

`map()`と比較するとわかり易いと思います。

### 1次元構造のコレクションを返す

```swift
let numbers = [1, 2, 3, 4]
let mapped = numbers.map { Array(count: $0, repeatedValue: $0) }
//[[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]
let flatMapped = numbers.flatMap{ Array(count: $0, repeatedValue: $0) }
//[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
```

### アンラップされた要素を返す

```swift
let possibleNumbers = ["1", "2", "three", "///4///", "5"]

let mapped: [Int?] = numbers.map { string in Int(string) }
//基本的にmapだとoptionalが返る
//[optional(1), optional(2), nil, nil, optional(5)]
//[1, 2, nil, nil, 5]

let flatMapped: [Int] = numbers.flatMap { string in Int(string) }
//アンラップされた値が返る
// [1, 2, 5]
```

### 優先度について

では、`nil`を含む多次元配列の場合はどうなるでしょうか。

```swift
let flatMapped = [[1], [2, 3], nil].flatMap { $0 }
//アンラップのみされた配列が返る
//[[1], [2, 3]]

let reFlatMapped = flatMapped.flatMap { $0 }
print(reFlatMapped)
//1次元配列を返す
//[1, 2, 3]
```

`nil`を含む多次元配列の場合は、アンラップされた配列を返す方が優先されるようですね。再びflatMap()で処理をすると1次元配列が返るようになります。


# <a id="closure">`Closure`について</a>
それぞれの高階関数の処理は引数に**`Closure`**が渡されているのですが、一見とっつきにくい書き方ですよね。書き方を理解するためには`Closure`を学ぶ必要があります。

## `sort()`の例から`Closure`を見る
***The Swift Programming Language***の[Closures](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html)ドキュメントを見ると`sort()`関数を例に説明されていますね。

```swift
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

var reversed = names.sort({ (s1: String, s2: String) -> Bool in
    return s1 > s2
})
//["Ewa", "Daniella", "Chris", "Barry", "Alex"]
```
要素が降順に並び替えられています。これは`integer`などの数字も扱えます。
`sort()`引数に`Closure`が渡されています。これは次のように書くとわかり易いと思います。

```swift
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = names.sort(backwards)
//["Ewa", "Daniella", "Chris", "Barry", "Alex"]
```
`s1`が`s2`より大きければ(アルファベト順が後)`true`を返し、`s1`と`s2`を入れ替えるというアルゴリスムが繰り返されていますね。
これを見てわかるように最初の`sort()`は引数に関数が渡されていたわけです。

`Closure`は一般的に次の書き方をします。

```swift:Closure
{
    (paramerters) -> return type in
        statements
}

```

```swift:Function
func function(paramerters) -> return type {
    statements
}
```
普通の関数と比較すると、名前がない関数のような書き方ですね。このことからも無名関数と呼ばれたりします。
さて、sort関数に渡していた`Closure`ですが、かなり短く書くことができます。順を追って確認してみましょう。

```swift
//一行でも書ける
reversed = names.sort( { (s1: String, s2: String) -> Bool in return s1 > s2 } )

//型推論をしてくれるので以下のようにも書ける
reversed = names.sort( { s1, s2 in return s1 > s2 } )

//(※1)returnを省略できる
reversed = names.sort( { s1, s2 in s1 > s2 } )

//(※2)引数を省略できる
reversed = names.sort( { $0 > $1 } )

//Closureを外に出すこともできる
reversed = names.sort() { $0 > $1 }

//()も省略できる
reversed = names.sort { $0 > $1 }

//このように省略することもできる。
reversed = names.sort(>)

```

- ※1 `sort()`は返り値が`Bool`で定義されていることから暗黙的に`s1 > s2`の結果を返してくれる

```swift:sort
@warn_unused_result(mutable_variant="sortInPlace")
    public func sort(@noescape isOrderedBefore: (Self.Generator.Element, Self.Generator.Element) -> Bool) -> [Self.Generator.Element]
```

- ※2 `Closure`は引数名は自動的に`$0`, `$1`, `$2`な連番で名前が付けられている。引数名を省略する場合は`in`も省略する

このように略式で書くことができます。順を追ってみると理解がしやすいのではないでしょうか。ただし可読性なども考慮して省略していく必要がありますね。


# 参考
- [Obj-Cな人のためのSwiftらしいコードを書くコツ３つ](http://wpdev.hatenablog.com/entry/2015/06/10/220836)
- [The Swift Programming Language A Swift Tour](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.html#//apple_ref/doc/uid/TP40014097-CH2-ID463)
- [The Swift Programming Language Closures](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html)
- [Swift Standard Library Reference SequenceType](https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_SequenceType_Protocol/index.html)
- [Swift Standard Library Reference CollectionType](https://developer.apple.com/library/watchos/documentation/Swift/Reference/Swift_CollectionType_Protocol/index.html)
- [swift life mapを学ぶ](http://swiftlife.hatenablog.jp/entry/2015/12/27/001414)
- [swift life CollectionType,SequenceTypeのmap()](http://swiftlife.hatenablog.jp/entry/2015/12/31/173847)
- [apple/swift/stdlib/public/core/Collection.swift](https://github.com/apple/swift/blob/master/stdlib/public/core/Collection.swift)
- [apple/swift/stdlib/public/core/Sequence.swift](https://github.com/apple/swift/blob/master/stdlib/public/core/Sequence.swift)
- [apple/swift/stdlib/public/core/IntegerArithmetic.swift.gyb](https://github.com/apple/swift/blob/master/stdlib/public/core/IntegerArithmetic.swift.gyb)
- [Functional Programming in Swift](http://www.slideshare.net/KazYoshikawa/functional-swift)
- [Swiftを書く時に気をつける小さな違い](http://qiita.com/kitasuke/items/3cc194542ee45a92bef2)
- [Swift 2のProtocol-Oriented Programmingっぽい書き方を理解する](http://qiita.com/dankogai/items/25c3bb1f493fba228467)
- [Swift 2.0の新しいflatMapが便利過ぎる](http://qiita.com/koher/items/6a95cb8edb04fb81f787)
- [mapとflatMapという便利メソッドを理解する](http://qiita.com/shimesaba/items/1a89cb5600454f91cc67)