3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-11-15

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

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

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

map

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ではもっと短いコードで書くことができます。

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がよくわからない方はこちらを確認してください。

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

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

結論

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

compactMap

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を使用します。

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

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

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

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

結論

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

flatMap

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文を2回繰り返しますよね...
でもflatMapを使えば楽ちんです!

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が存在しませんでした。
確か、flatMapcompactMapの機能も持っていたので非常にややこしくなっていたらしいです。

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

filter

struct User {
    /// ID
    let id: String
    /// 名前
    let name: String
    /// 性別 1:男性、2:女性、0:その他
    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を使えばもう少しかっこよく書くことができます。

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

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

forEach

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


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

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

結論

forEachは各要素に何かしらの処理を行うができる!

3
6
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?