Escrito por Reinder de Vries el 9 de julio de 2020 en Desarrollo de aplicaciones, Swift
En Swift se utiliza map()
, reduce()
y filter()
para realizar bucles en colecciones como matrices y diccionarios, sin utilizar un bucle for.
Las funciones de mapa, reducción y filtro provienen del ámbito de la programación funcional (FP). Se llaman funciones de orden superior, porque toman funciones como entrada. Está aplicando una función a una matriz, por ejemplo, para transformar sus datos.
Las funciones de mapa, Reducción y filtro de Swift pueden ser difíciles de entender. Especialmente si siempre has codificado bucles for in
para resolver problemas de iteración. En esta guía, aprenderá a utilizar las funciones map(_:)
, reduce(_:_:)
y filter(_:)
en Swift.
¡Comencemos!
- Introducción a Mapear, Reducir y Filtrar
- Inicio rápido: Funciones de orden superior en Swift
- Usando la Función de Mapa
- Usando la Función de Reducción
- Usando la Función de filtro
- Combinando Mapa, Reducir y Filtrar
- Lectura adicional
Introducción a Map, Reducir y Filtrar
Cuando está creando iOS aplicaciones, normalmente se utiliza programación orientada a objetos o de procedimiento. La programación funcional es diferente: solo trata de funciones. Sin variables, sin estado — sin bucles for, solo funciones.
El lenguaje de programación Swift se presta perfectamente para mezclar programación funcional con enfoques no funcionales, como OOP. No necesita escribir código funcional estrictamente, y la adopción de conceptos de programación funcional puede ayudarlo a aprender a codificar mejor.
Las funciones map(_:)
, reduce(_:_:)
y filter(_:)
se denominan funciones de orden superior, porque toman una función como entrada y devuelven funciones como salida. Técnicamente, Swift devuelve los resultados de una operación (p. ej. una matriz transformada) cuando se utilizan funciones de orden superior, mientras que un lenguaje funcional puro devolverá una colección de funciones. En Swift, las entradas para estas funciones son cierres.
Así es como funcionan:
- La función
map()
aplica una función a cada elemento de una colección. Piense en «mapear» o transformar un conjunto de valores en otro conjunto de valores. - La función
reduce()
convierte una colección en un valor. Piense en ello como combinar muchos valores en uno, como promediar un conjunto de números. - La función
filter()
simplemente devuelve valores que pasaron una instrucciónif
, y solo si esa condición resultó entrue
.
En caso de que estés pensando: «Mira, no necesito programación funcional o procesamiento de datos, ¡porque mis aplicaciones no hacen eso!»entonces no te detengas aquí. En proyectos de aplicaciones recientes, he utilizado Map, Reduce y Filter en múltiples ocasiones:
- Filtrar los valores de coste / ingresos con
filter(_:)
, para cumplir un umbral, antes de mostrar los valores en un gráfico de líneas - Promediando miles de clasificaciones de películas en un valor con
reduce(_:_:)
- Mapear algunas operaciones en una cadena con hashtags, transformándola en una colección normalizada, con
map(_:)
Podrías haber resuelto todos estos problemas con un bucle for, pero verás que usar map()
, reduce()
y filter()
da como resultado un código más conciso, legible y de mayor rendimiento.
Inicio Rápido: Funciones de orden superior en Swift
Nos centraremos en map()
, reduce()
y filter()
en este tutorial. Antes de seguir adelante, aquí encontrará un resumen rápido de las funciones de orden superior más comunes en Swift:
-
map(_:)
bucles sobre cada elemento de una secuencia, aplica una función a cada elemento y devuelve el resultado transformado -
reduce(_:_:)
bucles sobre cada elemento de una secuencia, los combina en un valor y devuelve el resultado combinado -
filter(_:)
bucles sobre cada elemento de una secuencia y devuelve una secuencia resultante que solo contiene elementos que satisfacen una función de filtrado dada -
flatMap(_:)
hace lo mismo quemap(_:)
, excepto que aplana la secuencia resultante, i. e. los arrays anidados no anidados o «aplanados»» -
compactMap(_:)
hace lo mismo quemap(_:)
, excepto que elimina valoresnil
de la secuencia resultante antes de devolverla
Puede usar estas funciones en matrices, diccionarios, conjuntos, rangos, secuencias y cualquier otro tipo Swift que pueda iterar. Si desea obtener más información sobre compactMap(_:)
y flatMap(_:)
, consulte este tutorial.
Varios tipos de Swift, como Array y Dictionary, tienen funciones que aceptan cierres como entrada. Una selección rápida:
-
contains(where:)
bucles sobre una colección, aplica un predicado (un cierre) a cada elemento, devuelve untrue
si un elemento satisface el predicado, de lo contrariofalse
-
first(where:)
recorre una colección, aplica un predicado (un cierre) a cada elemento y devuelve el elemento si satisface el predicado -
firstIndex(where:)
hace lo mismo quefirst(where:)
, excepto que devuelve el índice en lugar del valor
Puede obtener más información sobre estas funciones en este tutorial. El uso de where
en Swift también es interesante, puede obtener más información al respecto en este tutorial.
Ha visto las funciones» map «y» reduce » en Swift escritas como map(_:)
y reduce(_:_:)
a lo largo de este tutorial. Los guiones bajos y dos puntos en esas funciones son parte de la firma de la función, que es un formato especial para indicar los parámetros de la función. Por ejemplo, la función map(_:)
tiene un parámetro sin nombre, mientras que la función reduce(_:_:)
tiene dos. Puede obtener más información al respecto en este tutorial: Explicación de funciones en Swift.

Contrátese como desarrollador de iOS
Aprenda a crear aplicaciones de iOS 14 con Swift 5
Inscríbase en mi curso de desarrollo de iOS y aprenda a comenzar su carrera como desarrollador de iOS profesional.
Mediante la función Map
, la función map(_:)
recorre en bucle cada elemento de una colección y aplica una operación a cada elemento de la colección. Devuelve una colección de elementos resultantes, a los que se aplicó la operación.
veamos un ejemplo. Tenemos una variedad de temperaturas en grados Celsius que desea transformar en grados Fahrenheit.
Podrías usar un bucle for, como este:
let celsius = var fahrenheit: = for value in celsius { fahrenheit += }print(fahrenheit)// Output:
El código funciona bien, pero es demasiado detallado. Necesita una variable «auxiliar» mutable fahrenheit
para almacenar las conversiones calculadas a medida que trabaja a través de ellas, y necesita 3 líneas de código para la conversión en sí.
Así es como podemos hacer lo mismo con la función map(_:)
:
sea fahrenheit = celsius.mapa { $0 * (9/5) + 32 }
impresión (fahrenheit)
Incluso puedes hacer todo eso en una sola línea:
.map { * (9/5) + 32 }
¿Qué pasa aquí?
- Se define una constante
celsius
, una matriz de dobles e inicializada con unos pocos valores Celsius aleatorios. - La función
map(_:)
se llama en el arraycelsius
. La función tiene un argumento, un cierre, que convierte de Celsius a Fahrenheit. - Finalmente, se imprime el resultado: la matriz convertida, de Celsius a Fahrenheit.
La función map(_:)
transforma una matriz en otra, aplicando una función a cada elemento de la matriz. El cierre * (9/5) + 32
toma el valor de entrada en Celsius y devuelve un valor en Fahrenheit. La matriz resultante de map(_:)
se construye a partir de esos valores convertidos.
Echemos un vistazo más de cerca al cierre. Si has trabajado con cierres antes, reconocerás la sintaxis de cierre a mano corta. Es una forma más corta de codificar un cierre, al omitir gran parte de su sintaxis.
Aquí hay una alternativa menos concisa:
let celsius = let fahrenheit = celsius.map({ (value: Double) -> Double in return value * (9/5) + 32})print(fahrenheit)
La llamada real a la función map(_:)
, y su cierre, es este:
··· = celsius.map({ (value: Double) -> Double in return value * (9/5) + 32})
¿Qué está pasando ahí? La función map(_:)
se llama en el array celsius
. Toma un argumento: un cierre de tipo (Double) -> Double
.
La primera parte de la clausura, empezando con {
, indica que este cierre tiene un parámetro value
de tipo Double
, y el cierre devuelve un valor de tipo Double
. El cuerpo de cierre, a partir de return
, simplemente devuelve el resultado del cálculo Celsius a Fahrenheit.
Si comparas la sintaxis de cierre a mano corta con el código expandido anterior, verás que:
- Los paréntesis de función
(
y)
se omiten, porque puede omitirlos cuando el último parámetro de una llamada a función es un cierre. - La parte
() -> in
se puede omitir, porque Swift puede inferir que está utilizando un parámetroDouble
como entrada, y se espera que devuelva unDouble
. Ahora que ha omitido la variablevalue
, puede usar la mano corta.
- La instrucción
return
también se puede omitir, porque se espera que este cierre devuelva el resultado de una expresión de todos modos.
Aunque el ejemplo de código anterior utiliza tipos Double
, no está limitado a estos tipos. El tipo resultante de una función map()
puede tener un tipo diferente al que se le agrega, y también puede usar map()
en una Dictionary
.
¡Pasemos a reduce(_:_:)
!
Usando la función Reducir
La función reduce(_:_:)
recorre todos los elementos de una colección y los reduce a un valor. Piense en ello como la combinación de múltiples valores en uno.
La función reducir es quizás la función de mapa, reducción y filtro más difícil de comprender. ¿Cómo se puede pasar de una colección de valores a un solo valor?
Algunos ejemplos:
- Crear una suma de múltiples valores, es decir,
3 + 4 + 5 = 12
- Concatenar una colección de cadenas, es decir,
= "Zaphod, Trillian, Ford"
- Promediar un conjunto de valores, es decir,
(7 + 3 + 10) / 3 = 7/3 + 3/3 + 10/3 = 6.667
En el procesamiento de datos, puede imaginar muchos escenarios cuando operaciones simples como estas son útiles. Al igual que antes, puede resolver cualquiera de estos problemas con un bucle for, pero reduce(_:_:)
es simplemente más corto y rápido.
Aquí está cómo:
let suma = valores.reducir (0,+)
imprimir (suma)
La función reduce(_:_:)
toma dos argumentos, un valor inicial y un cierre. En el código anterior, proporcionamos el operador +
, que también es una función con dos parámetros.
También puede proporcionar su propio cierre, por supuesto:
let promedio = valores.reducir(0.0) { $0 + $1 } / Doble(valores.recuento)
impresión (promedio)
En el ejemplo anterior, estás calculando el promedio de tres números. Los tipos de los valores en el código son todos Double
. Primero sumamos todos los números, y luego los dividimos por la cantidad de números.
La función reduce(_:_:)
es diferente de dos maneras:
- La función
reduce(_:_:)
tiene dos parámetros sin nombre; el valor inicial y el cierre - El cierre que se proporciona a
reduce(_:_:)
también tiene dos parámetros; el resultado actual de la reducción y el nuevo valor que está a punto de reducirse
Aquí, mira esto:
let suma = valores.reducir (0) {
imprimir(«\($0) + \($1) = \($0 + $1)»)
retorno $0 + $1
}
imprimir (suma)
En el ejemplo anterior, puede ver claramente y
, los 2 parámetros de los cierres. Cuando ejecuta el código, esta es la salida que obtiene:
0 + 7 = 77 + 3 = 1010 + 10 = 2020
¿Ves cómo empezamos con 0
y luego agregamos 7
? En el siguiente paso, tomaremos 7
, el valor de reducción actual, y agregaremos 3
, el valor «siguiente» en la reducción.
Aquí hay otra forma de verlo:
0 + 7(0 + 7) + 3((0 + 7) + 3) + 10
Esto también deja claro por qué necesita un valor inicial para reduce(_:_:)
, porque ese es el primer parámetro del cierre.
La reducción puede ser difícil de comprender. Es importante entender que estás aplicando iterativamente una operación, como +
, a un conjunto de valores hasta que solo te queda un valor. Reduce literalmente la cantidad de valores.
¡Pasemos a filter(_:)
!
Usando la función de filtro
La función filter
recorre todos los elementos de una colección y devuelve una colección que contiene solo elementos que cumplen una condición de inclusión.
Es como aplicar una instrucción if
-a una colección, y solo mantener los valores que pasan la condición.
Aquí, mira esto:
let even = valores.filtro { $0.Es múltiple (of: 2)}
impresión (par)
En el ejemplo anterior, está filtrando números de values
que son pares. La función isMultiple(of:)
devuelve true
cuando se puede dividir por
2
, y false
de lo contrario.
A diferencia de map(_:)
y reduce(_:_:)
, el cierre filter(_:)
necesita devolver un booleano, por lo que puede ser true
o false
. Cuando el cierre devuelve true
, el valor se mantiene, y cuando se devuelve false
, el valor se omite. Así es como filter(_:)
filtra la matriz de entrada.
Este es un ejemplo un poco más claro, con el cierre expandido:
let values = let even = values.filter({ (value:Int) -> Bool in return value.isMultiple(of: 2)})print(even) // Output:
En el ejemplo, el cierre devuelve un valor booleano, indicado con -> Bool
. Se proporciona un parámetro, el elemento de la colección, y devuelve el resultado de isMultiple(of:)
. ¡Genial!
Combinar Map, Reducir y Filtrar
¿Puede combinar las funciones map()
, reduce()
y filter()
? ¡Claro que puedes!
Digamos que tenemos una clase de estudiantes. Ya sabes el año en que nació cada estudiante. Desea calcular la edad combinada de todos los estudiantes nacidos en o después de 2000.
Así es como lo haces:
let years =
let sum = years.filtro({ $0 >= 2000 }).mapa ({ ahora-now 0}).reducir (0,+)
imprimir (suma)
El ejemplo de código anterior utiliza encadenamiento. Utiliza el resultado de una función como entrada para otra, combinando map-reduce-filter. La función map()
se llama en la matriz de resultados de la función filter()
, y la función reduce()
se llama en el resultado de la función map()
. ¡Órale!
El código en sí es simple:
- Cree una constante
now
yyears
, y asígnele un montón de años. - Filtrar los años que están por debajo de 2000, p. ej. mantenga los que
>= 2000
estrue
- Transforme cada año en una edad, restando el año de
now
- Agregue todas las edades, reduciendo con
+
Tomemos un ejemplo más interesante. Compruebe el código siguiente, tomado del tutorial sobre FizzBuzz:
interruptor (i % 3 == 0, i % 5 == 0)
{
caso (true, false):
volver «Fizz»
caso (falso, verdadero):
volver «Buzz»
caso (true, true):
volver «FizzBuzz»
por defecto:
retorno » \(i)»
}
}
let result = Array (2…100).mapa(fizzbuzz).reducir(«1», { $0 + «, » + $1 })
imprimir (resultado)
Ver ¿Qué está pasando? Estamos transformando una matriz con números del 2 al 100 en «Fizz», «Buzz» o «FizzBuzz» con map(_:)
, según las reglas del juego. Finalmente, estamos reduciendo esa matriz de cadenas en una cadena grande con reduce(_:_:)
, combinando todos los valores. ¡Genial!
Lectura adicional
¿Y si tuvieras que codificar todo esto con bucles for in
? Usarías mucho más código. Y eso es el poder del filtro de reducción de mapas: es más conciso, a menudo más fácil de leer y, admítalo, ¡bastante genial!
¿Quieres saber más? Consulte estos recursos:
- Cómo Usar «dónde» en Swift
- Mapa plano Y Mapa compacto Explicados En Swift
- La Guía Definitiva de Cierres en Swift
- Cómo: Encontrar Un Elemento En Una Matriz En Swift
- Jugar Con Código: Búsqueda Binaria En Swift
- Comience con Xcode Playgrounds

Contrátese como desarrollador de iOS
Aprenda a crear aplicaciones de iOS 14 con Swift 5
Inscríbase en mi curso de desarrollo de iOS y aprenda a comenzar su carrera como desarrollador de iOS profesional.