Le mécanisme reduce fait partie des opérations fonctionnelles sur les collections de données et est venu en Swift des langages fonctionnels (map-reduce, fold). Historiquement, cette fonction permet de transformer n'importe quelle collection en une seule valeur agrégée (par exemple, la somme, le produit, la concaténation de chaînes, etc.), en parcourant tous ses éléments et en accumulant le résultat. Le problème de base qu'il résout est l'agrégation succincte, lisible et sans bogues des données au lieu de boucles manuelles.
En Swift, reduce est défini comme une méthode de collections :
func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
Cela signifie que vous spécifiez une valeur initiale, puis vous écrivez une fonction qui renvoie une nouvelle valeur agrégée pour chaque élément et l'accumulateur actuel.
Exemple de code :
let numbers = [1, 2, 3, 4] let sum = numbers.reduce(0) { $0 + $1 } // 10 let joined = numbers.reduce("") { $0 + String($1) } // "1234"
Caractéristiques clés :
Comment fonctionne reduce sur une collection vide ?
Reduce est appliqué à chaque élément de la collection. Si la collection est vide, la valeur initiale est renvoyée, aucune invocation de closure ne sera faite.
Exemple de code :
let empty: [Int] = [] let sum = empty.reduce(100) { $0 + $1 } // 100
Peut-on modifier la collection d'origine avec reduce ?
Non, reduce est une fonction pure, elle ne modifie pas la collection d'origine. Tous les changements ne se produisent qu'avec l'accumulateur.
Quelle est la différence entre reduce et reduce(into:) ?
reduce(into:) permet de muter l'accumulateur à chaque passage et fonctionne plus efficacement avec les types value, où la création d'une nouvelle copie (copy-on-write) est coûteuse.
Exemple de code :
let nums = [1, 2, 3] let squares = nums.reduce(into: []) { (result: inout [Int], item) in result.append(item * item) } // squares == [1, 4, 9]
Un développeur voulait sommer les prix des produits stockés dans un tableau products. Il a utilisé reduce avec une valeur initiale de 0.0, mais la closure était conçue de telle sorte qu'elle retournait parfois une somme négative en cas de réductions, ce qui a conduit à des résultats incorrects et à des problèmes de calcul de la taxe.
Avantages :
Inconvénients :
Utilisation de reduce(into:) pour créer un cache à partir d'un tableau d'entités par id :
let objects: [Entity] = ... let cache = objects.reduce(into: [:]) { $0[$1.id] = $1 }
Avantages :
Inconvénients :