1
2

More than 3 years have passed since last update.

Swiftにおける配列操作関数

Last updated at Posted at 2021-02-14

配列操作関数とは、その名の通り配列を操作するための関数である。

forEach

よくあるfor文を、配列操作関数forEachに置き換えた場合

let arr1 = [1, 2, 3, 4, 5]

do {
    for v in arr1 {
        print(v)
    }
}
do {
    arr1.forEach { (v) in
    print(v)
    }
}
1
2
3
4
5

中身がクロージャになっているので、好きな関数を渡すことができる。

ドキュメントには、

Calls the given closure on each element in the sequence in the same order as a for-in loop.
(for-inループと同じ順序で、シーケンス内の各要素に対して与えられたクロージャを呼び出します。)

とある。

filter

filterは、中身のクロージャがtrueの時だけ抜き出すというもの。

do {
    let arr2 = arr1.filter { (v) -> Bool in
        v % 2 == 0
    }

    for v in arr2 {
        print(v)
    }
}
2
4

偶数かどうかの評価がtrueだった時に、arr2に追加される。

以下ドキュメント

Returns an array containing, in order, the elements of the sequence that satisfy the given predicate.
(与えられた式の結果を満たすときに、配列の中身を返します。)

上記の内容は、メソッドを繋げて表現することも可能。

do {
    arr1.filter { (v) -> Bool in
        v % 2 == 0
    }.forEach { (v) in
        print(v)
    }
}
2
4

filterを通してからforEachで回した。

map

mapは、要素ひとつずつに処理をすることができる。
下記のように、ひとつずつの型を変えることが可能である。(最も使用頻度が高い)

do {
    let arr2 = arr1.map { (v) -> String in
        String(v) + "です"
    }

    for v in arr2 {
        print(v)
    }
}
1です
2です
3です
4です
5です

上の例は、戻り値をStringにした場合で、
配列の要素一つずつをStringに変える、という意味である。

以下ドキュメント

Returns an array containing the results of mapping the given closure over the sequence’s elements.
(指定したクロージャをシーケンスの要素にマッピングした結果を含む配列を返します。)

reduce

reduceは、要素を用いて結果をまとめたいときなどに用いる。

do {
    let v = arr1.reduce("") { (result, v) -> String in
        result + "\(v)です, "
    }
    print(v)
}
1です, 2です, 3です, 4です, 5です, 

まずは初期値を自由に設定できる。今回は、""(空文字)を渡している。
resultはカラ文字、vには配列の要素が入る。

返り値はStringなので、String型の結果を式の中で構築する。

最初は、"空文字 + 1です, "の String が返る。
2周目は、引数のresultの中には直前に返された "1です, " が入っており、 vにはarr1の次の要素である2が来る。

これが繰り返されることで、一つのresult が更新されていく。

以下ドキュメント

Returns the result of combining the elements of the sequence using the given closure.
(指定したクロージャを用いてシーケンスの要素を結合した結果を返します。)

実践的な例

id と name プロパティを持つユーザーモデルを例に、より実践的な例をあげる。

以下は、filterで条件を絞り(この場合、偶数だけに絞る)、 mapでユーザーモデルを構築している。

struct User {
    var id: Int = 0
    var name: String = ""
}

do {
    let users = arr1.filter { (v) -> Bool in
        v % 2 == 0
    }.map { (v) -> User in
        User(id: v, name: "偶数\(v)です")
    }

    for user in users {
        print("id: \(user.id), name:\(user.name)")
    }
}
id: 2, name:偶数2です
id: 4, name:偶数4です

配列からユーザーモデルを生成できた。
検索の絞り込みなどをアプリ側で行いたいときなどは、こういった機能が必要になってくる。

省略記法


do {
    arr1.filter { $0 % 2 == 0 }.forEach { print($0) }

    arr1
        .filter { $0 % 2 != 0 }
        .map { User(id: $0, name: "奇数\($0)です") }
        .forEach {
            print("id: \($0.id), name: \($0.name)")
    }
}
2
4
id: 1, name: 奇数1です
id: 3, name: 奇数3です
id: 5, name: 奇数5です

$0は、クロージャ式でいうところの、パラメータ v を表している。
1行しかない場合、それが return を意味することになる。

一方で、下記のように2行以上にした場合、return にならないので、エラーとなる。

do {
    arr1.filter {
        print("ああ")
        $0 % 2 == 0 }.forEach { print($0) } // ここでエラー発生. Missing return in a closure expected to return 'Bool'; did you mean to return the last expression?
}

Boolを返せと怒られている。

printでデバックした時などは、このエラーが出るので注意が必要である。

1
2
0

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
1
2