Escrito por Reinder de Vries el 12 de julio de 2020 en Desarrollo de aplicaciones, Swift

Mapa plano y mapa compacto explicados en Swift

Swift tiene un montón de funciones que son útiles para transformar colecciones y secuencias. En este tutorial, discutiremos map(_:), flatMap(_:) y compactMap(_:).

Esto es en lo que nos centraremos:

  1. Cómo map(_:) transforma una colección o secuencia aplicándole un cierre
  2. Cómo flatMap(_:) puede aplanar un array de entrada, después de llamar a map(_:)
  3. Cómo compactMap(_:) elimina nil del array de entrada

En un tutorial anterior, hemos discutido cómo puede utilizar filter(_:) y reduce(_:). Estas funciones de orden superior son súper útiles para transformar colecciones, de una manera concisa y perspicaz.

Listo? Vamos.

  1. Uso de la función Map en Swift
  2. Uso de la función flatMap
  3. Uso de la función CompactMap
  4. ¿Por qué usar flatMap y CompactMap?
  5. Más información

¿Aún no está familiarizado con los cierres o las funciones de orden superior? Asegúrese de leer primero sobre ellos:

  • La Guía Definitiva de Cierres en Swift
  • Mapear, Reducir y Filtrar en Swift

Utilizando la función de mapa en Swift

Como actualización rápida de funciones de orden superior en Swift, nuestro punto de partida es la función map(_:). Esta función aplica una transformación a cada uno de los elementos de una secuencia, como una matriz o un diccionario.

Este es un ejemplo:

let numbers =
let result = numbers.mapa({ $0 * $0 })
imprimir (resultado)
Ocultar advertencias

Desglosemos esto:

Primero, estamos creando un array numbers con unos pocos valores enteros. Luego, la función map(_:) se llama a numbers y su resultado se asigna a result.

La función map(_:) tiene un parámetro, un cierre, que devuelve el resultado de . El corresponde al primer parámetro del cierre, es decir, el número de numbers que se está transformando.

estamos calculando el cuadrado de cada número en numbers. En esencia, la operación se llama a cada número en numbers, y el array resultante se asigna a result. Está transformando, o» mapeando», una matriz en otra.

Transformar una matriz con map(_:) es similar a usar un bucle for, pero mucho más conciso. Así:

let numbers = var result = ()for number in numbers { result += }print(result)

Aquí hay otra forma de verlo. Con map(_:), la matriz de números de entrada se transforma en otra matriz de números. Así:

2 => 2 * 2 => 43 => 3 * 3 => 94 => 4 * 4 => 165 => 5 * 5 => 25

Las funciones como map(_:) se llaman funciones de orden superior, porque toman una función como entrada en lugar de valores ordinarios. Las funciones de orden superior también pueden generar funciones, lo que es útil para un paradigma de programación llamado programación funcional.

Técnicamente, puede llamar a funciones de orden superior como map(_:) en cualquier secuencia. Esto incluye colecciones como matrices, diccionarios y conjuntos, rangos como 1...100 y los llamados iteradores. Cualquier cosa que parezca una «lista» de valores, básicamente.

Discutiremos por qué las funciones de orden superior son útiles al final de este tutorial. Pasemos primero a aprender sobre flatMap(_:) y compactMap(_:).

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.

Usando la función flatMap

La función flatMap(_:) es similar a map(_:) excepto que «aplana» la matriz resultante. Este es un ejemplo:

let numbers =,,]
let result = numbers.Mapa plano ({{0 })
imprimir (resultado)
Ocultar advertencias

El código anterior comienza con una matriz anidada de enteros. La matriz numbers consiste en una matriz de 3 matrices, cada una de las cuales contiene 3 números.

El cierre { } simplemente devuelve el primer argumento del cierre, es decir, los arrays anidados individuales. No hay transformación ni operación. Sin embargo, cuando llamas a flatMap(_:) en la matriz numbers, en lugar de map(_:), terminas con una matriz aplanada de números individuales. A diferencia de la matriz de entrada numbers, la matriz de resultados no contiene matrices anidadas.

veamos otro ejemplo. Imagine que está trabajando con 4 grupos de jirafas y desea crear un solo grupo de jirafas que sean más altas que una cierta altura. Así es como lo haces:

let jirafas=,,]
let más alto = jirafas.Mapa plano ({ $0.filtro({ $0 > 10 }) })
impresión (más alta)
Ocultar advertencias

Vea cómo giraffes contiene una matriz de matrices? En el código anterior, se llama a la función filter(_:) en cada matriz anidada dentro de giraffes. Solo queremos enteros (jirafas!) que sean mayores que 10. Las matrices resultantes se aplanan en una matriz «plana», y se asignan a tallest.

Considere lo que pasaría si hubiéramos usado map(_:) en lugar de flatMap(_:). La matriz resultante no se aplanaría. En su lugar, sería esto:

, , ]

Es importante tener en cuenta que la función flatMap(_:) llama a map(_:) en los elementos de la matriz primero y luego los aplana. Es por eso que algo como lo siguiente no funciona:

let numbers = , , ]let result = numbers.flatMap({  * 2 })

En el código anterior, se refiere a los arrays dentro de los números. Multiplicar un array por dos es imposible, por eso este código no funciona.

Es inteligente pensar en el mapeo plano como ver una matriz en una dimensión menos. Comienza con una matriz bidimensional y termina con una matriz unidimensional después de flatMap(_:).

¿Qué hay de usar flatMap(_:) con opcionales? Veamos eso a continuación.

El nombre «mapa compacto» se basa en la idea de que la eliminación de elementos nil de una matriz hace que la matriz sea más compacta. Del mismo modo, el nombre «mapa plano» proviene de aplanar la matriz. Y «mapeo» es un concepto de matemáticas, en el que se asocian los valores de un conjunto con otro conjunto.

Usando la función CompactMap

La función compactMap(_:) elimina valores nil de la matriz de entrada. Es muy útil cuando se trabaja con opcionales.

Antes de Swift 4.1, la función flatMap(_:) (arriba) también se puede usar para filtrar valores nil de matrices aplanadas. Desde Swift 4.1+, ahora usa compactMap(_:) explícito para este propósito.

Este es un ejemplo:

let numbers =
let result = numbers.compactMap ({Int (Int 0) })
imprimir (resultado)
Ocultar advertencias

¿Ver qué sucede? La parte más importante del código es Int(). Esto toma una cadena individual de numbers con e intenta convertir a un entero, con el inicializador Int().

Este inicializador Int() es fallable: puede devolver nil, un opcional, por lo que su tipo de retorno es Int?. Como resultado, el tipo de retorno de la transformación de asignación es , una matriz de enteros opcionales.

La función compactMap(_:) elimina automáticamente elementos nil de la matriz devuelta, después de llamar a map(_:) en ella. Como tal, su tipo de retorno no es opcional.

En el código anterior, el tipo de result es . Si hubiera utilizado map(_:), el tipo devuelto habría sido . Y habría necesitado un paso adicional para desenvolver los valores de la matriz, para trabajar con ellos.

¿Por qué usar flatMap y CompactMap?

Antes de discutir los casos de uso del mundo real de flatmap y compactmap, hagamos un resumen rápido de estas funciones de orden superior y sus propósitos.

  1. La función map(_:) aplica un cierre a una colección de entrada y devuelve la colección transformada
  2. La función flatMap(_:) hace lo mismo, y también aplana la colección resultante
  3. La función compactMap(_:) hace lo mismo que map(_:), y también elimina nil de la colección resultante

Trabajar con map(_:), flatMap(_:) y compactMap(_:) en abstracto hace que a veces sea difícil imaginar sus casos de uso práctico. Discutamos por qué querrías usarlos.

Usar funciones como map (_:) para aplicar transformaciones a secuencias tiene algunas ventajas:

  • Es más conciso que usar un bucle for, porque no necesita variables temporales ni un bloque for in { } de varias líneas.
  • Normalmente puede escribir una llamada a map(_:) en una línea, lo que (por lo general) hace que su código sea más legible.
  • Las funciones como map(_:) se pueden encadenar, por lo que puede aplicar varias transformaciones a una secuencia una por una.

En general, las funciones de orden superior son útiles porque permiten aplicar una función a una secuencia de valores. En lugar de codificar la transformación de forma procedimental, solo puede aplicar la función y obtener un resultado de vuelta.

El caso de uso más práctico para flatMap(_:) es trabajar con valores de entrada agrupados o anidados, pero el valor de salida que desea debe ser unidimensional.

En una aplicación de música, por ejemplo, puedes tener 3 arreglos: canciones, artistas y listas de reproducción. Los combinas en una matriz, llamas a flatMap(_:) en ella, seleccionas las canciones, artistas y listas de reproducción para las que isFavorite es true y terminas con una lista plana de elementos que han sido favoritos.

Un caso de uso práctico para compactMap(_:) es trabajar con una transformación que puede devolver nil. Se ahorra unos pocos pasos triviales al dejar que compactMap(_:) filtre valores nil de inmediato. Un beneficio adicional es el tipo de retorno no opcional de compactMap(_:); la función filter(_:), en comparación, habría devuelto un valor opcional si filtrara nil.

Puede combinar flatMap(_:) y compactMap(_:), e incluso filter(_:) o reduce(_:_:). Imagina que estás creando una aplicación de redes sociales. Quieres construir una línea de tiempo de publicaciones para un usuario. Utiliza 3 consultas para seleccionar ID de publicación para el usuario, por ejemplo, de publicaciones de seguidores, anuncios y temas de tendencias.

  • Puede usar map(_:) para expandir estos ID en objetos Post reales
  • Puede usar flatMap(_:) para aplanar los 3 grupos en una colección
  • Puede usar compactMap(_:) para descartar publicaciones que no se pudieron expandir

¡Limpio!

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.

Leer más

Vale la pena aprender sobre map(_:), flatMap(_:) y compactMap(_:), porque hacen que su código sea más conciso y legible. Puedes agregar programación más funcional al código de tu app. Una vez que te acostumbras a ellos, no puedes creer que puedas hacer tu trabajo sin ellos.

Especialmente las diferencias entre map(_:), flatMap(_:) y compactMap(_:) merecen señalarse. El primero aplica una transformación a una secuencia, el segundo aplana el array resultante y el tercero elimina valores nil antes de devolver su resultado. ¡Órale!

Deja una respuesta

Tu dirección de correo electrónico no será publicada.