El mecanismo reduce se relaciona con operaciones funcionales sobre colecciones de datos y llegó a Swift desde lenguajes funcionales (map-reduce, fold). Históricamente, esta función permite transformar cualquier colección en un único valor agregado (por ejemplo, suma, producto, concatenación de cadenas, etc.), recorriendo todos sus elementos y acumulando el resultado. El problema básico que resuelve es la agregación de datos de manera concisa, legible y libre de errores en lugar de bucles manuales.
En Swift, reduce está definido como un método de colecciones:
func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
Esto significa que se especifica un valor inicial y luego se escribe una función que para cada elemento y el acumulador actual devuelve un nuevo valor agregado.
Ejemplo de código:
let numbers = [1, 2, 3, 4] let sum = numbers.reduce(0) { $0 + $1 } // 10 let joined = numbers.reduce("") { $0 + String($1) } // "1234"
Características clave:
¿Cómo funciona reduce en una colección vacía?
Reduce se aplica a cada elemento de la colección. Si la colección está vacía, se devuelve el valor inicial, no habrá llamadas a la closure.
Ejemplo de código:
let empty: [Int] = [] let sum = empty.reduce(100) { $0 + $1 } // 100
¿Se puede usar reduce para cambiar la colección original?
No, reduce es una función pura, no modifica la colección original. Todos los cambios ocurren solo con el acumulador.
¿Cuál es la diferencia entre reduce y reduce(into:)?
reduce(into:) permite mutar el acumulador en cada paso y funciona de manera más eficiente con tipos de valor, donde la creación de una nueva copia (copy-on-write) es costosa.
Ejemplo de código:
let nums = [1, 2, 3] let squares = nums.reduce(into: []) { (result: inout [Int], item) in result.append(item * item) } // squares == [1, 4, 9]
Un desarrollador quería sumar los precios de los productos almacenados en un arreglo de productos. Usó reduce con un valor inicial de 0.0, pero la closure estaba diseñada de tal manera que a veces devolvía una suma negativa debido a los descuentos, lo que resultó en totales incorrectos y problemas con el cálculo del impuesto.
Pros:
Contras:
Se utilizó reduce(into:) para crear una caché de un arreglo de entidades por id:
let objects: [Entity] = ... let cache = objects.reduce(into: [:]) { $0[$1.id] = $1 }
Pros:
Contras: