#21 Swiftで学ぶコレクション操作の応用(フィルタ・マップ的な考え方)の基本

はじめに

Swiftで配列(複数の値をまとめて扱う入れ物、Array)を使っていると、いくつかの処理をしたくなる場面によく出会います。たとえば「条件に合う要素だけ取り出したい」「全要素を別の形に変換したい」「全要素を集計して1つの値にしたい」といった場面です。こうした処理はfor文でも書けますが、Swiftにはfilter・map・reduceという専用のメソッド(コレクション操作の応用)が用意されています。これらを使うと、目的が一目で分かる短いコードになります。この記事では、この3つの基本的な使い方と、初心者がつまずきやすいポイントを解説します。

filter:条件に合う要素だけを絞り込む

filterは、配列の中から「条件を満たす要素だけ」を新しい配列として取り出すメソッドです。条件を判定する処理(クロージャと呼ばれる、その場で書ける小さな関数のようなもの)を引数として渡します。

let numbers = [1, 2, 3, 4, 5, 6]
let evens = numbers.filter { $0 % 2 == 0 }
// evens は [2, 4, 6]

$0は「クロージャに渡された1つ目の引数」を指す省略記法で、ここでは配列の各要素を表します。{ $0 % 2 == 0 }は「2で割った余りが0(=偶数)」という条件です。filterは条件がtrueだった要素だけを集めて新しい配列を返すので、元のnumbersは変更されません。この「元の配列を壊さず、新しい配列を作る」性質は、Swiftのコレクション操作全体に共通する特徴です。意図せず元データを書き換えてしまうバグを防いでくれます。

map:全要素を別の形に変換する

mapは、配列の全要素に同じ処理を適用し、変換後の値を新しい配列として返します。

let names = ["taro", "hanako", "jiro"]
let upperNames = names.map { $0.uppercased() }
// upperNames は ["TARO", "HANAKO", "JIRO"]

ここではuppercased()(文字列を大文字に変換するメソッド)を各要素に適用しています。mapは要素数を変えずに中身だけ変換したいときに使う、という点がfilterとの違いです。

reduce:全要素を1つの値にまとめる

reduceは、配列の全要素を順番に処理しながら1つの値に集約(合計・連結など)するメソッドです。初期値と、要素を1つずつ足し込んでいく処理を指定します。

let numbers = [1, 2, 3, 4, 5]
let total = numbers.reduce(0) { $0 + $1 }
// total は 15

最初の引数0が初期値で、クロージャの$0がここまでの計算結果、$1が今処理している要素です。合計を求める場合はさらに省略してnumbers.reduce(0, +)と書くこともできます。慣れないうちは省略せずに{ $0 + $1 }の形で書き、動きが理解できてから短く書き直すのがおすすめです。

3つを組み合わせる

これらは連続して呼び出す(メソッドチェーンと呼びます)ことができます。

let scores = [55, 80, 42, 90, 65]
let passedTotal = scores
    .filter { $0 >= 60 }
    .map { $0 * 1.1 }
    .reduce(0, +)

「60点以上を絞り込み→1.1倍のボーナス点に変換→合計する」という処理が、for文を使わずに1行の流れとして書けます。処理の意図がコードの見た目からそのまま読み取れるのが大きな利点です。ただし、チェーンが長くなりすぎると1行で何をしているか逆に読みにくくなるため、複雑な処理は途中で変数に分けて分割するとよいでしょう。

他言語との違い・つまずきやすい点

PythonやJavaScriptにも同様の機能(内包表記やArray.prototype.mapなど)がありますが、Swiftのfilter・map・reduceは型(値の種類)に厳密です。mapで数値配列を文字列配列に変換すると、戻り値の型も自動的に[String]になります。慣れないうちは、変換後の型が何になっているかXcode(Swiftの開発ツール)の型推論の補完で確認しながら書くと安心です。また、空の配列にreduceを使っても、初期値がそのまま返るだけでエラーにはなりません。ただしfirstや強制アンラップを使う処理では、空配列がクラッシュの原因になりやすいため注意しましょう。

まとめ

filterは絞り込み、mapは変換、reduceは集約、とそれぞれ役割がはっきりしています。最初はfor文で書いてから「これはfilterで書けないか」と置き換えてみると、自然に使い分けが身についていきます。短く書けることよりも、まずは「何をしたいコードなのか」が読み手に伝わることを意識して使ってみてください。

関連記事


本ページはプロモーションを含みます。

参考書籍(PR)

Swiftをもっと学びたい方には「これからつくる iPhoneアプリ開発入門」がおすすめです。


PR

コードを書かずに自動化したい方へ

「学んだけど自分の作業に組み込む時間がない」という方向けに、ダブルクリックで動く Windows専用の自動化ツールをオーダーメイドで作成しています。気になる方は こちらをご覧ください。

コメント

このブログの人気の投稿

#25 Rustで学ぶAI API(ChatGPT等)の呼び出し方の基本

#8 C++で学ぶ文字列操作の基本

#16 TypeScriptで学ぶ辞書型(マップ)の基本