Swift: map()でゴチャついた処理をreduce(into:)でスッキリ
こんつぁ、しょーです。
イテレーション、繰り返し処理の話をしよう。
reduce(into:)
はちょっと理解あまりしていなく使用を避けていた節があり、map系
でゴリゴリしていたらこれ使えるよってアドバイスもらって使い方がわかったので備忘録。
想定
APIレスポンスを元にTableView
にて、セクションを切ってアイテムをリスト表示させたいケースがありました。
Header
SectionHeader
は別途使用していたのと、viewをいじいじしたCustomView
を使用したかったなどで、header
はCustomCell
を使用したかった。
Cell
普通にcustomCell
こんな感じのリストがレスポンスとして返ってくるとします。
これをこうしたい。
なんならアイテムが無ければこうもしたい。
TableView.CellForRowAt
で操作しやすくするためにベースとなる配列を作成したい、というところ。
条件
- ヘッダーの文字列 + それに対応したアイテムリスト を作成したい
- アイテムの数に比例したセル数を作成する必要があるので、個数も対応したい
- アイテムがない場合はヘッダーも要らないので、そのセクションは排除したい
TableView
の実装方法にもよりますが、割愛します。
これを実現させるために以下のような配列が必要。(1つの案として)
こうすることで、cellForAtRow
ではswitch sections[indexPath.section]
を切って別々のカスタムセルを付与できるし、
配列なのでindexPath.row/section
の数も合います。
では作ろうということで、以下を実装しました。
コード
前置き長くなりましたがreduce(into:)
の本題。
最初はmap系
駆使してやりました。
第一形態
kind & namesJP
をセットで操作したいのでタプル型の配列を作る- アイテムがない場合はセクションを排除したいので、
isEmpty
判定でなければnil
を返す compactMap
でnil
掃除- 一時的に作成した配列と、最終的に使用したい配列の型が異なるので
flatMap
で欲しいものだけ取り出す
これでも動きますが、マップマップしてちょっと騒がしい。
ということで提案いただいたその1が以下。
第二形態
一時的な配列を作成しないで一気に作成。少し静かになりました。
しかし、これはあと一回進化を残しています。その意味が分か
ここでreduce(into:)
を使用します。
第三形態
なんということでしょう、ほぼほぼ2行になりました。
凝縮していますが、まだリーダブルの範囲です。慣れればサクッとリーディングできそうです。
reduce(into:)の使い方
こういう時にreduce(into:)
使えるかも?と閃くキッカケとして
- 何かをベースに配列や辞書(ベースとは別の型)を作成したい時
nil
の場合、該当する値を排除したい時(nilを許容しない場合)
flatMap / compactMap
などカリカリする時があれば閃ければいいです。
APIレスポンスを操作するときなどマッピングする機会はたくさんあると思うので使い所はありそうですし、スッキリしていいですね。
まとめ
マッピング系処理のネタが増えてよかった。
読みもそうだけど、実装できるか判断するまで慣れが必要そうね。
お疲れっす!
最近のコメント