Reinder de Vriesによって2020年7月12日にSwiftのアプリ開発で書かれました
で説明されていますSwiftにはコレクションやシーケンスの変換に便利な関数がたくさんあります。 このチュートリアルでは、map(_:)
、flatMap(_:)
、compactMap(_:)
について説明します。
ここでは、私たちが焦点を当てるものです:
-
map(_:)
クロージャを適用してコレクションまたはシーケンスを変換する方法 -
flatMap(_:)
を呼び出した後に入力配列をフラット化する方法map(_:)
-
compactMap(_:)
が入力配列からnil
を削除する方法
前のチュートリアルでは、
を使用する方法について説明しました。1699>とreduce(_:)
。 これらの高階関数は、簡潔で洞察に満ちた方法でコレクションを変換するのに非常に役立ちます。
準備はできましたか? 行こう
- SwiftでMap関数を使用する
- FlatMap関数を使用する
- CompactMap関数を使用する
- なぜFlatMapとCompactMapを使用するのですか?
- 続きを読む
クロージャや高次関数にはまだ慣れていませんか? それらの最初に読むことを確認してください:
- Swiftでのクロージャの究極のガイド
- Swiftでのマップ、縮小、およびフィルタ
Swift
のMap関数を使用して、Swiftの高次関数の簡単な復習として、私たちの出発点はmap(_:)
関数です。 この関数は、配列や辞書のように、シーケンス内の各要素に変換を適用します。
ここに例があります:
let result=numbers.地図({ $0 * $0 })
印刷(結果)
それを分解してみましょう:
まず、いくつかの整数値を持つ配列numbers
を作成しています。 次に、関数map(_:)
がnumbers
で呼び出され、その結果がresult
に割り当てられます。
map(_:)
関数には、の結果を返すクロージャというパラメータがあります。
は、クロージャの最初のパラメータ、つまり変換されている
numbers
からの数値に対応します。
私たちはnumbers
のすべての数の二乗を計算しています。 本質的には、演算は
numbers
内のすべての数値で呼び出され、結果の配列はresult
に割り当てられます。 ある配列を別の配列に変換するか、”マッピング”しています。
map(_:)
で配列を変換することは、forループを使用するのと似ていますが、はるかに簡潔です。 このように:
let numbers = var result = ()for number in numbers { result += }print(result)
これを見る別の方法があります。 map(_:)
を使用すると、数値の入力配列は別の数値配列に変換されます。 このように:
2 => 2 * 2 => 43 => 3 * 3 => 94 => 4 * 4 => 165 => 5 * 5 => 25
map(_:)
のような関数は、通常の値とは対照的に入力として関数を取るため、高次関数と呼ばれます。 高階関数は関数を出力することもでき、これは関数型プログラミングと呼ばれるプログラミングパラダイムに有用である。
技術的には、任意のシーケンスでmap(_:)
のような高次関数を呼び出すことができます。 これには、配列、辞書、セットのようなコレクション、1...100
のような範囲、いわゆるイテレータが含まれます。 基本的には、値の「リスト」のように見えるもの。
このチュートリアルの最後で、なぜ高階関数が有用なのかについて説明します。 まず、flatMap(_:)
とcompactMap(_:)
について学びましょう。

Ios開発者として雇われる
Swift5でiOS14アプリを構築する方法を学ぶ
私のiOS開発コースにサインアップし、プロのiOS開発者としてのキャリアを開始す
FlatMap関数
を使用すると、flatMap(_:)
関数は、結果の配列を”フラット化”することを除いて、map(_:)
に似ています。 ここに例があります:
let result=numbers.flatMap({$0})
print(result)
上記のコードは、整数のネストされた配列から始まります。 numbers
配列は、3つの配列の配列で構成され、それぞれに3つの数値が含まれています。
クロージャ{ }
は、単にクロージャの最初の引数、すなわち個々のネストされた配列を返します。 変換や操作は行われていません。 ただし、numbers
配列でflatMap(_:)
を呼び出すと、map(_:)
ではなく、個々の数字のフラット化された配列になります。 入力配列numbers
とは異なり、結果配列にはネストされた配列が含まれていません!
別の例を見てみましょう。 あなたがキリンの4つのグループで作業していて、特定の高さよりも背の高いキリンの単一のグループを作成したいと想像してください。 ここでは、それを行う方法です:
キリン=,,]
キリン=,,]
キリン=,,]
キリン=,,]flatMap({$0.フィルター({ $0 > 10 }) })
プリント(一番背の高い)
giraffes
に配列の配列が含まれている方法を参照してください。 上記のコードでは、関数filter(_:)
はgiraffes
内のすべてのネストされた配列で呼び出されます。 私たちは整数だけをしたいです(キリン!)より大きい10
。 結果の配列は、1つの「フラット」配列に平坦化され、tallest
に割り当てられます。
flatMap(_:)
の代わりにmap(_:)
を使用した場合、どうなるか考えてみてください。 結果の配列は平坦化されません。 代わりに、それはこれだろう:
, , ]
flatMap(_:)
関数は、最初に配列項目に対してmap(_:)
を呼び出し、次にそれをフラット化することに注意することが重要です。 そのため、次のようなものが機能しません:
let numbers = , , ]let result = numbers.flatMap({ * 2 })
上記のコードでは、はnumbers内の配列を参照しています。 配列に2を乗算することは不可能なので、このコードは機能しません。
フラットマッピングについては、一つの次元の配列を見ると考えるのが賢明です。 2次元の配列から始まり、flatMap(_:)
の後に1次元の配列になります。
オプションでflatMap(_:)
を使用するのはどうですか? 次にそれを見てみましょう。
“compact map”という名前は、配列からnil
項目を削除すると配列がよりコンパクトになるという考えに基づいています。 同様に、”flat map”という名前は、配列を平坦化することから来ています。 そして、「マッピング」は数学の概念であり、あるセットの値を別のセットに関連付けることができます。
CompactMap関数
を使用すると、compactMap(_:)
関数は入力配列からnil
値を削除します。 Optionalsで作業するとき、それは超便利です。
スウィフト4の前に。図1に示すように、flatMap(_:)
関数(上記)を使用して、フラット化された配列からnil
値をフィルタリングすることもできます。 Swift4.1以降では、この目的のために明示的なcompactMap(_:)
を使用するようになりました。
ここに例があります:
let result=numbers.compactMap({Int($0)})
print(result)
何が起こるかを参照してください。 コードの最も重要な部分はInt()
です。 これは、numbers
からで個々の文字列を受け取り、
Int()
初期化子を使用して整数に変換しようとします。
このInt()
初期化子は失敗可能です:それはnil
を返すことができます–オプション–その戻り値の型はInt?
です。 その結果、マッピング変換の戻り値の型は–オプションの整数の配列です。
compactMap(_:)
関数は、map(_:)
を呼び出した後、返された配列からnil
要素を自動的に削除します。 そのため、戻り値の型は省略可能ではありません。上記のコードでは、result
のタイプはです。
map(_:)
を使用した場合、戻り値の型はになります。 そして、あなたはそれらを扱うために、配列から値をアンラップするための余分なステップが必要だったでしょう。
なぜFlatMapとCompactMapを使用するのですか?
flatmapとcompactmapの実際の使用例を議論する前に、これらの高階関数とその目的を簡単に要約しましょう。
-
map(_:)
関数は入力コレクションにクロージャを適用し、変換されたコレクションを返します -
flatMap(_:)
関数は同じことを行い、結果のコレクションもフラット化します -
compactMap(_:)
関数はmap(_:)
と同じことを行い、結果のコレクションからnil
を削除します
抽象的にmap(_:)
、flatMap(_:)
、compactMap(_:)
を使用すると、実際のユースケースを想像するのが難しいことがあります。 あなたがそれらを使用したいと思う理由を議論してみましょう。
map(_:)のような関数を使用してシーケンスに変換を適用するには、いくつかの利点があります:
- 一時変数と複数行の
for in { }
ブロックは必要ないため、for
ループを使用するよりも簡潔です。 - 通常、
map(_:)
への呼び出しを1行で書くことができます。 -
map(_:)
のような関数を連鎖させることができるので、シーケンスに複数の変換を一つずつ適用することができます。
一般に、高階関数は値のシーケンスに関数を適用できるため便利です。 変換を手続き的にコーディングする代わりに、関数を適用して結果を返すことができます。
flatMap(_:)
の最も実用的なユースケースは、グループ化またはネストされた入力値を扱うことですが、必要な出力値は一次元である必要があります。
たとえば、音楽アプリでは、曲、アーティスト、プレイリストの3つの配列を持つことができます。 それらを1つの配列に結合し、その上でflatMap(_:)
を呼び出し、isFavorite
がtrue
である曲、アーティスト、プレイリストを選択し、お気に入りの項目のフラットリストが1つにな
compactMap(_:)
の実用的なユースケースは、nil
を返すことができる変換で作業しています。 compactMap(_:)
にnil
の値をすぐに除外させることで、いくつかの簡単な手順を節約できます。 これと比較して、nil
を除外した場合、filter(_:)
関数はオプションの値を返しました。
flatMap(_:)
とcompactMap(_:)
、さらにはfilter(_:)
またはreduce(_:_:)
を組み合わせることができます。 ソーシャルメディアアプリを構築しているとします。 ユーザーの投稿のタイムラインを作成する必要があります。 3つのクエリを使用して、フォロワーの投稿、広告、トレンドトピックなど、ユーザーの投稿Idを選択します。
-
map(_:)
を使用してこれらのIdを実際のPost
オブジェクトに展開できます -
flatMap(_:)
を使用して3つのグループを1つのコレクションにフラット化できます -
compactMap(_:)
を使用して、展開できなかった投稿を破棄できます
Neat!

Ios開発者として雇われる
Swift5でiOS14アプリを構築する方法を学ぶ
私のiOS開発コースにサインアップし、プロのiOS開発者としてのキャリアを開始す
さらに読む
コードをより簡潔で読みやすくするため、map(_:)
、flatMap(_:)
、compactMap(_:)
について学ぶことは価値があります。 アプリのコードに関数型プログラミングを追加できます。 あなたがそれらに慣れると、あなたはそれらなしであなたの仕事をすることができると信じることができません。
特にmap(_:)
、flatMap(_:)
、compactMap(_:)
の違いは指摘する価値があります。 最初の1つはシーケンスに変換を適用し、2番目の1つは結果の配列を平坦化し、3番目の1つは結果を返す前にnil
値を削除します。 すごい!