【初心者向け】Swiftらしくコーティングできるようになろう！

Swiftはモダンな言語の一つです。
毎年メジャーアップデートもされるので最新の言語の一つとも言えます(毎回対応するの大変ですが...)。

今回はモダンな言語によく取り入れられているmap、filter、forEachを紹介します。
他の言語でもよく使うので、覚えておいて損はないかと思います。

使い慣れるとどんな処理も、mapを使って表現できないか考えるようになります。


## map
### 例

```swift
struct User {
    let id: String
    let name: String
}

let users = [
    User(id: "111", name: "aaa"),
    User(id: "112", name: "bbb"),
    User(id: "113", name: "ccc"),
    User(id: "114", name: "ddd"),
    User(id: "115", name: "eee"),
    User(id: "116", name: "fff"),
]

var result = [String]()
for user in users {
    result.append(user.id)
}

print(result)
// ["111", "112", "113", "114", "115", "116"]
```

UserのidをまとめてString型の配列を作成しています。
大学の授業とかだとこんな感じでコーティングしましょうと習うかと思います。

しかし、Swiftではもっと短いコードで書くことができます。

```swift
struct User {
    let id: String
    let name: String
}

let users = [
    User(id: "111", name: "aaa"),
    User(id: "112", name: "bbb"),
    User(id: "113", name: "ccc"),
    User(id: "114", name: "ddd"),
    User(id: "115", name: "eee"),
    User(id: "116", name: "fff"),
]

let result = users.map { $0.id }

print(result)
// ["111", "112", "113", "114", "115", "116"]
```

mapを使うことでたった一行で書けてしまいます！
`$0`がよくわからない方はこちらを確認してください。 

```swift
let result = users.map { user in
    user.id
}
```

こちらの記述方法でなんとなくわかるかと思います(for~inとそっくり)。
`user in`を省略すると`$0`で表現することができるのです。

### 結論
#### **mapは各要素に何かしらの処理を行い、結果を配列にして返すことができる！**


## compactMap
### 例

```swift
struct User {
    let id: String
    let name: String
}

let users = [
    User(id: "111", name: "aaa"),
    User(id: "112", name: "bbb"),
    User(id: "113", name: "ccc"),
    User(id: "a114", name: "ddd"),
    User(id: "a115", name: "eee"),
    User(id: "a116", name: "fff"),
]

let stringUserIdList = users.map { $0.id }
var result = [Int]()
for stringUserId in stringUserIdList {
    if let id = Int(stringUserId) {
        result.append(id)
    }
}

print(result)
// [111, 112, 113]
```

先程はmapを使って簡単にStringの配列を作成しました。
しかし、idをStringではなく`Int`に変換して配列にしたい場合もあるかと思います。
今のままだと結局、ソースコードが長くなってしまいます。

このような場合には`compactMap`を使用します。

```swift
let result = users
    .compactMap { Int($0.id) }

print(result)
// [111, 112, 113]
```

`users.map { Int($0.id) }`ではInt?の配列が返却されます。
当然、StringからIntにキャストしようとすると１００％キャストできるわけではないのでInt?が返却されます。

しかし`compactMap`は、`nil`なものは取り除きます。
そのため、返却される型はIntの配列になります。

### 結論
#### **compactMapは各要素に何かしらの処理を行い、結果をnilのない配列にして返すことができる！**


## flatMap
### 例

```swift
let users = [
    [
        User(id: "101", name: "man1"),
        User(id: "102", name: "man2"),
        User(id: "103", name: "man3"),
        User(id: "104", name: "man4"),
        User(id: "105", name: "man5")
    ],
    [
        User(id: "201", name: "women1"),
        User(id: "202", name: "women2"),
        User(id: "203", name: "women3"),
        User(id: "204", name: "women4"),
        User(id: "205", name: "women5")
    ]
]
var result = [String]()

// genderという名前はよろしくない...
for gender in users {
    for user in gender {
        result.append(user.id)
    }
}

print(result)
// ["101, "102", "103", "104", "105", "201", "202", "203", "204", "205"]
```

このように、男性女性別々になっている連想配列があったとします。
このusersから全てのidを抜き出すときはこんな感じで実装するかと思います。

当然for文を２回繰り返しますよね...
でも`flatMap`を使えば楽ちんです！

```swift
let result = users
    .flatMap { $0 }
    .map { $0.id }

print(result)
// ["101, "102", "103", "104", "105", "201", "202", "203", "204", "205"]
```

`flatMap`は文字の通りフラットにしてくれます。

### 結論
#### **flatMapは階層の深い要素をフラットにしてくれる！**

## map、compactMap、flatMapのメリット
- ソースコードが短くなる
- 知識がある同士なら可読性が上がる
    - 知らないメンバーがいるのであれば勉強会を開催して共有するべき
- 変数名に悩まなくて済む
    - 複雑な処理ほど中間の要素を保持する変数の命名が増えるのでありがたい


## 参考までに...
以前のSwiftバージョンでは`compactMap`が存在しませんでした。
確か、`flatMap`が`compactMap`の機能も持っていたので非常にややこしくなっていたらしいです。

最新のバージョンではその問題は解消されたので頻繁に利用していきましょう！

## filter

### 例

```swift
struct User {
    /// ID
    let id: String
    /// 名前
    let name: String
    /// 性別 1：男性、２：女性、０：その他
    let gender: Int
    /// 身長
    let height: Float
}

let users = [
    User(id: "001",
         name: "たんじろう",
         gender: 1,
         height: 165),
    User(id: "102",
         name: "ねずこ",
         gender: 2,
         height: 153.0),
    User(id: "103",
         name: "ぜんいつ",
         gender: 1,
         height: 165.5),
    User(id: "104",
          name: "いのすけ",
          gender: 1,
          height: 164.0)
]
// 男性のみを取得
var mens = [User]()
// 164cm以下のUserのみを取得
var result = [User]()
for user in users {
    if user.gender == 1 {
        mens.append(user)
    }
    if user.height <= 164.0 {
        result.append(user)
    }
}
print(mens)
print(result)
```

mapを紹介したとき同様、
取得した結果を格納する変数(配列)を用意して、for文内のif文で通過したものを変数に格納しています。

`filter`を使えばもう少しかっこよく書くことができます。

```swift
// 男性のみを取得
let result = users.filter { $0.gender == 1 }
// 164cm以下の男性のみを取得
let result = users
    .filter { $0.gender == 1 }
    .filter { $0.height <= 164.0 }
```

積極的に使っていきましょう！！

## forEach

使う目的は`for~in`と同様です。
省略して書きたい場合に`forEach`を使うことが多いです。

```swift

// for~in
for user in users {
    print(user)
}

// forEach
users.forEach { print($0) }
```

### 結論
#### **forEachは各要素に何かしらの処理を行うができる！**