Écrit par Reinder de Vries le 12 juillet 2020 dans Développement d’applications, Swift

 FlatMap et CompactMap Expliqués dans Swift

Swift a un tas de fonctions utiles pour transformer des collections et des séquences. Dans ce tutoriel, nous allons discuter de map(_:), flatMap(_:) et compactMap(_:).

Voici ce sur quoi nous allons nous concentrer:

  1. Comment map(_:) transforme une collection ou une séquence en lui appliquant une fermeture
  2. Comment flatMap(_:) peut aplatir un tableau d’entrée, après avoir appelé map(_:)
  3. Comment compactMap(_:) supprime nil du tableau d’entrée

Dans un tutoriel précédent, nous avons discuté de la façon dont vous pouvez utiliser

  1. Comment map(_:)
  2. Comment compactMap(_:) supprime nil du tableau d’entrée

filter(_:) et reduce(_:). Ces fonctions d’ordre supérieur sont très utiles pour transformer les collections, de manière concise et perspicace.

Prêt? Allons-y.

  1. Utilisation de la Fonction Map dans Swift
  2. Utilisation de la Fonction FlatMap
  3. Utilisation de la Fonction CompactMap
  4. Pourquoi Utiliser FlatMap et CompactMap ?
  5. Lectures complémentaires

Vous ne connaissez pas encore les fermetures ou les fonctions d’ordre supérieur? Assurez-vous de les lire en premier:

  • Le Guide ultime des fermetures dans Swift
  • Cartographiez, Réduisez et filtrez dans Swift

En utilisant la fonction Map dans Swift

Comme rappel rapide sur les fonctions d’ordre supérieur dans Swift, notre point de départ est la fonction map(_:). Cette fonction applique une transformation à chacun des éléments d’une séquence, comme un tableau ou un dictionnaire.

Voici un exemple:

let numbers=
let result=numbers.carte({ $0 * $0 })
imprimer (résultat)
Masquer les avertissements

Décomposons cela:

Tout d’abord, nous créons un tableau numbers avec quelques valeurs entières. Ensuite, la fonction map(_:) est appelée sur numbers et son résultat est affecté à result.

La fonction map(_:) a un paramètre, une fermeture, qui renvoie le résultat de . Le correspond au premier paramètre de la fermeture, c’est-à-dire le nombre de numbers qui est transformé.

Nous calculons le carré de chaque nombre dans numbers. En substance, l’opération est appelée sur chaque nombre de numbers, et le tableau résultant est affecté à result. Vous transformez – ou « mappez » – un tableau en un autre.

Transformer un tableau avec map(_:) est similaire à l’utilisation d’une boucle for, mais beaucoup plus concis. Comme ça:

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

Voici une autre façon de le regarder. Avec map(_:), le tableau de nombres d’entrée est transformé en un autre tableau de nombres. Comme ça:

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

Des fonctions comme map(_:) sont appelées fonctions d’ordre supérieur, car elles prennent une fonction en entrée par opposition aux valeurs ordinaires. Les fonctions d’ordre supérieur peuvent également produire des fonctions, ce qui est utile pour un paradigme de programmation appelé programmation fonctionnelle.

Techniquement, vous pouvez appeler des fonctions d’ordre supérieur comme map(_:) sur n’importe quelle séquence. Cela inclut les collections telles que les tableaux, les dictionnaires et les ensembles, les plages telles que 1...100 et les soi-disant itérateurs. Tout ce qui ressemble à une « liste » de valeurs, en gros.

Nous expliquerons pourquoi les fonctions d’ordre supérieur sont utiles à la fin de ce tutoriel. Passons d’abord à en savoir plus sur flatMap(_:) et compactMap(_:).

Soyez embauché en tant que développeur iOS

Apprenez à créer des applications iOS 14 avec Swift 5

Inscrivez-vous à mon cours de développement iOS et apprenez à démarrer votre carrière en tant que développeur iOS professionnel.

En utilisant la fonction FlatMap

, la fonction flatMap(_:) est similaire à map(_:), sauf qu’elle « aplatit » le tableau résultant. Voici un exemple:

let numbers=,,]
let result=numbers.flatMap({00})
imprimer (résultat)
Masquer les avertissements

Le code ci-dessus commence par un tableau imbriqué d’entiers. Le tableau numbers se compose d’un tableau de 3 tableaux, chacun contenant 3 nombres.

La fermeture { } renvoie simplement le premier argument de la fermeture, c’est-à-dire les tableaux imbriqués individuels. Aucune transformation ou opération n’a lieu. Lorsque vous appelez flatMap(_:) sur le tableau numbers, au lieu de map(_:), vous vous retrouvez avec un tableau aplati de nombres individuels. Contrairement au tableau d’entrée numbers, le tableau de résultat ne contient pas de tableaux imbriqués !

Regardons un autre exemple. Imaginez que vous travaillez avec 4 groupes de girafes et que vous souhaitez créer un seul groupe de girafes plus hautes qu’une certaine hauteur. Voici comment vous faites cela:

let girafes=,,]
let plus haut = girafes.Carte plate ({00.filtre({ $0 > 10 }) })
imprimer (le plus haut)
Masquer les avertissements

Voir comment giraffes contient un tableau de tableaux? Dans le code ci-dessus, la fonction filter(_:) est appelée sur chaque tableau imbriqué à l’intérieur de giraffes. Nous ne voulons que des entiers (girafes!) qui sont supérieures à 10. Les tableaux résultants sont aplatis en un tableau « plat » et affectés à tallest.

Considérez ce qui se passerait si nous avions utilisé map(_:) au lieu de flatMap(_:). Le tableau résultant ne serait pas aplati. Au lieu de cela, ce serait ceci:

, , ]

Il est important de noter que la fonction flatMap(_:) appelle d’abord map(_:) sur les éléments du tableau, puis l’aplatit. C’est pourquoi quelque chose comme ce qui suit ne fonctionne pas:

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

Dans le code ci-dessus, fait référence aux tableaux à l’intérieur des nombres. Multiplier un tableau par deux est impossible, c’est pourquoi ce code ne fonctionne pas.

Il est intelligent de penser à la mise à plat comme voyant un tableau dans une dimension de moins. Vous commencez avec un tableau bidimensionnel et vous vous retrouvez avec un tableau unidimensionnel après flatMap(_:).

Qu’en est-il de l’utilisation de flatMap(_:) avec des options? Regardons ça ensuite.

Le nom « carte compacte » est basé sur l’idée que la suppression des éléments nil d’un tableau rend le tableau plus compact. De même, le nom « carte plate » vient de l’aplatissement du tableau. Et le « mappage » est un concept des mathématiques, où vous associez les valeurs d’un ensemble à un autre ensemble.

Utilisation de la fonction CompactMap

La fonction compactMap(_:) supprime les valeurs nil du tableau d’entrée. C’est super utile lorsque vous travaillez avec des options.

Avant Swift 4.1, la fonction flatMap(_:) (ci-dessus) peut également être utilisée pour filtrer les valeurs nil des tableaux aplatis. Depuis Swift 4.1+, vous utilisez maintenant le compactMap(_:) explicite à cette fin.

Voici un exemple:

let numbers=
let result=numbers.compactMap({Int(00)})
print(résultat)
Masquer les avertissements

Voir ce qui se passe ? La partie la plus importante du code est Int(). Cela prend une chaîne individuelle de numbers avec et tente de convertir en un entier, avec l’initialiseur Int().

Cet initialiseur Int() est défaillant : il peut renvoyer nil – une option – donc son type de retour est Int?. En conséquence, le type de retour de la transformation de mappage est – un tableau d’entiers facultatifs.

La fonction compactMap(_:) supprime automatiquement les éléments nil du tableau renvoyé, après avoir appelé map(_:) dessus. En tant que tel, son type de retour n’est pas facultatif.

Dans le code ci-dessus, le type de result est . Si vous aviez utilisé map(_:), le type de retour aurait été . Et vous auriez eu besoin d’une étape supplémentaire pour déballer les valeurs du tableau, pour travailler avec elles.

Pourquoi utiliser FlatMap et CompactMap ?

Avant de discuter des cas d’utilisation réels de flatmap et compactmap, résumons rapidement ces fonctions d’ordre supérieur et leurs objectifs.

  1. La fonction map(_:) applique une fermeture à une collection d’entrée et renvoie la collection transformée
  2. La fonction flatMap(_:) fait la même chose, et elle aplatit également la collection résultante
  3. La fonction compactMap(_:) fait la même chose que map(_:), et elle supprime également nil de la collection résultante

Travailler avec map(_:), flatMap(_:) et compactMap(_:) dans l’abstrait rend parfois difficile d’imaginer leurs cas d’utilisation pratiques. Discutons pourquoi vous voudriez les utiliser.

L’utilisation de fonctions telles que map(_:) pour appliquer des transformations à des séquences présente quelques avantages:

  • C’est plus concis que d’utiliser une boucle for, car vous n’avez pas besoin de variables temporaires et d’un bloc multi-lignes for in { }.
  • Vous pouvez généralement écrire un appel à map(_:) sur une ligne, ce qui (généralement) rend votre code plus lisible.
  • Des fonctions comme map(_:) peuvent être enchaînées, vous pouvez donc appliquer plusieurs transformations à une séquence une par une.

En général, les fonctions d’ordre supérieur sont utiles car elles vous permettent d’appliquer une fonction à une séquence de valeurs. Au lieu de coder la transformation de manière procédurale, vous pouvez simplement appliquer la fonction et récupérer un résultat.

Le cas d’utilisation le plus pratique pour flatMap(_:) consiste à travailler avec des valeurs d’entrée groupées ou imbriquées, mais la valeur de sortie souhaitée doit être unidimensionnelle.

Vous pouvez, dans une application musicale par exemple, avoir 3 tableaux: chansons, artistes et listes de lecture. Vous les combinez dans un tableau, appelez flatMap(_:) dessus, sélectionnez les chansons, les artistes et les listes de lecture pour lesquels isFavorite est true, et vous vous retrouvez avec une liste plate d’éléments qui ont été favorisés.

Un cas d’utilisation pratique pour compactMap(_:) fonctionne avec une transformation qui peut renvoyer nil. Vous vous épargnez quelques étapes triviales en laissant compactMap(_:) filtrer immédiatement les valeurs nil. Un avantage supplémentaire est le type de retour non facultatif de compactMap(_:); la fonction filter(_:), en comparaison, aurait renvoyé une valeur facultative si vous aviez filtré nil.

Vous pouvez combiner flatMap(_:) et compactMap(_:), et même filter(_:) ou reduce(_:_:). Imaginez que vous construisez une application de médias sociaux. Vous souhaitez construire une chronologie des publications pour un utilisateur. Vous utilisez 3 requêtes pour sélectionner les ID de publication de l’utilisateur, par exemple dans les publications des abonnés, les publicités et les sujets de tendance.

  • Vous pouvez utiliser map(_:) pour étendre ces ID en objets Post réels
  • Vous pouvez utiliser flatMap(_:) pour aplatir les 3 groupes en une seule collection
  • Vous pouvez utiliser compactMap(_:) pour supprimer les publications qui n’ont pas pu être étendues

Neat!

Soyez embauché en tant que développeur iOS

Apprenez à créer des applications iOS 14 avec Swift 5

Inscrivez-vous à mon cours de développement iOS et apprenez à démarrer votre carrière en tant que développeur iOS professionnel.

Pour en savoir plus

Il vaut la peine de se renseigner sur map(_:), flatMap(_:) et compactMap(_:), car ils rendent votre code plus concis et lisible. Vous pouvez ajouter une programmation plus fonctionnelle au code de votre application. Une fois que vous vous y êtes habitué, vous ne pouvez pas croire que vous pourriez faire votre travail sans eux.

En particulier, les différences entre map(_:), flatMap(_:) et compactMap(_:) méritent d’être soulignées. Le premier applique une transformation à une séquence, le second aplatit le tableau résultant et le troisième supprime les valeurs nil avant de renvoyer son résultat. Fantastique!

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.