[Swift] Array（Sequence）のmap/forEachで途中リターン

## これはなに？

途中リターン出来ます

## 実例

では実際にやってみましょう

### 簡単な例

0から始まる無限数列を途中まで順に表示します。（無限ではない）

#### forを使った方法

```swift
func f() {
    for i in (0...) {
        let j = i * 2
        if j > 10 {
            return
        }
        print(j)
    }
}

f()
```

実行結果

```sh
0
2
4
6
8
10
```

#### forEachを使った方法

```swift
func g() {
    (0...)
        .lazy
        .map { $0 * 2 }
        .prefix { $0 <= 10 }
        .forEach { print($0) }
}

g()
```

実行結果

```sh
0
2
4
6
8
10
```

実行結果は同じです。

#### 解説

`lazy`と`prefix`を使って途中リターンを実現しています。

`Sequence`の`lazy`プロパティは`LazySequence`を返します。
`LazySequence`は`LazySequenceProtocol`という遅延評価を行う各種メソッドを要求するプロトコルに準拠したタイプです。
`LazySequenceProtocol`に準拠するタイプには`LazySequence`以外にもいろいろありますので気になる方は調べてください。
ここでいう遅延評価とは`map`などの関数を引数に取るメソッドが渡された関数を即座に実行するのではなく、実際に値が必要になるまで関数の適用（評価）を遅延させる事をいいます。
`map`以外にも`prefix`や`filter`なども遅延評価されます。

もし、関数`g`に`lazy`がなかった場合を想像してください。
元となる`Sequence`の要素は無限にありますから`map`関数の処理が終わる事はありません。（実際には無限ではないので`Int.max`を超えたところでクラッシュします）
`lazy`と`prefix`を使う事で必要な要素のみを処理し途中で終了させる事が出来るのです。

終了条件の部分に注目してみましょう。
forを使った場合の終了条件は

```swift
if j > 10 {
    return
}
```

です。`lazy`を使用した場合の終了条件は

```swift
    .prefix { $0 <= 10 }
```

です。
これらの条件はちょうど逆になっています。

終了条件が

```swift
if condition {
    return // あるいは break
}
```
となっている途中リターンのあるforループは

```swift
    .prefix { !condition }
```
を終了条件とした`LazySequence`で置き換える事が可能であるという事です。

### 2重ループ

2重ループの内側のループで行われる途中リターンはどうでしょう。

#### forを使った方法

```swift
func f() {
    for i in (0...) {
        for j in (0...5) {
            // iとjの積が10以上になったら終了する
            if i * j > 10 {
                return 
            }
            print(i, j)
        }
    }
}

f()
```

実行結果

```sh
0 0
0 1
0 2
0 3
0 4
0 5
1 0
1 1
1 2
1 3
1 4
1 5
2 0
2 1
2 2
2 3
2 4
2 5
3 0
3 1
3 2
3 3
```

#### forEachを使った方法

```swift

func g() {
    (0...)
        .lazy
        .flatMap { i in
            (0...5)
                .lazy
                .map { j in (i, j, i * j) }
        }
        .prefix { $0.2 <= 10 } // iとjの積が10未満の間
        .forEach { print($0.0, $0.1) }
}

g()
```

実行結果

```sh
0 0
0 1
0 2
0 3
0 4
0 5
1 0
1 1
1 2
1 3
1 4
1 5
2 0
2 1
2 2
2 3
2 4
2 5
3 0
3 1
3 2
3 3
```

こちらが同等の処理です。

####　解説
初見だとかなりややこしく見えますが、基本的には同じです。

```swift
if condition {
    return // あるいは break
}
```
を

```swift
    .prefix { !condition }
```

に書き換えています。

２重にループを行う場合`map`を使うと2次元配列になるため`flatMap`を使用する必要がある事に注意してください。
また、イテレータの値が必要な場合はタプルなどを利用して次の処理に渡す必要があります。

### ちょっと寄り道

途中リターンではありませんが、条件文と`contiune`をつかって処理を飛ばす事もよくあります。
これも`LazySequence`を使って書く事が可能です。

#### forを使った方法

```swift
// 0から9までの奇数を出力する
func f() {
    for i in (0..<10) {
        if i.isMultiple(of: 2) {
            continue
        }
        print(i)
    }
}

f()
```

実行結果

```sh
1
3
5
7
9
```

#### forEachを使った方法

```swift
func g() {
    (0..<10)
        .lazy
        .filter { !$0.isMultiple(of: 2) }
        .forEach { print($0) }
}

g()
```

実行結果

```sh
1
3
5
7
9
```

#### 解説

`contiue`を使った処理の省略は `filter`を使って書き換える事が可能です。
この場合も条件は逆になります。

```swift
if condition {
    continue
}
```
は

```swift

   .filter { !condition }
```
で書き換える事が出来ます。



## まとめ

forなどの繰り返し構文による途中リターンのほとんどはArray/Sequenceのmap/forEachなどに変換可能です。


### メリットは？

え？
それ、必要ですか？

あー、そこになかったらないですね。

## おまけ

これはfor/whileじゃ無理でしょ？という途中リターンの例をお待ちしています。