reduceメカニズムはデータコレクションに対する関数型操作に関連しており、Swiftはこの概念を関数型言語(map-reduce、fold)から導入しました。この機能は、任意のコレクションを単一の集約値(例えば、合計、積、文字列の結合など)に変換するために使用され、その全要素を通過して結果を蓄積します。基本的な問題は、手動のループの代わりに、簡潔で読みやすく、バグのないデータの集約を提供することです。
Swiftでは、reduceはコレクションメソッドとして定義されています:
func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
これは、初期値を指定し、その後、各要素と現在のアキュムレーターに対して新しい集約値を返す関数を書くことを意味します。
コード例:
let numbers = [1, 2, 3, 4] let sum = numbers.reduce(0) { $0 + $1 } // 10 let joined = numbers.reduce("") { $0 + String($1) } // "1234"
主な特徴:
空のコレクションに対するreduceはどのように機能しますか?
reduceはコレクションの各要素に適用されます。コレクションが空の場合、初期値が返され、closureの呼び出しはありません。
コード例:
let empty: [Int] = [] let sum = empty.reduce(100) { $0 + $1 } // 100
reduceを使って元のコレクションを変更することはできますか?
できません、reduceは純粋な関数であり、元のコレクションを変更しません。すべての変更はアキュムレーターにのみ行われます。
reduceとreduce(into:)の違いは何ですか?
reduce(into:)は、各反復でアキュムレーターを変更でき、値タイプに対してより効率的に機能し、新しいコピーを作成する(copy-on-write)のがコスト高い場合に適しています。
コード例:
let nums = [1, 2, 3] let squares = nums.reduce(into: []) { (result: inout [Int], item) in result.append(item * item) } // squares == [1, 4, 9]
開発者は、products配列に保存されている商品の価格を合計したかった。初期値0.0でreduceを使用したが、closureは時折割引がある場合に負の合計値を返すことがあり、これにより不正確な最終結果と税計算の問題が発生した。
利点:
欠点:
エンティティの配列からidでキャッシュを作成するためにreduce(into:)を使用しました:
let objects: [Entity] = ... let cache = objects.reduce(into: [:]) { $0[$1.id] = $1 }
利点:
欠点: