配列操作関数とは、その名の通り配列を操作するための関数である。
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でデバックした時などは、このエラーが出るので注意が必要である。