Better Programming

Advice for programmers.

Follow publication

Map, CompactMap, and FlatMap in Swift

Alessandro Manilii
Better Programming
Published in
4 min readFeb 7, 2022
Source: Undraw

In a normal app, it is very common to work with arrays. Often we need to take all the elements, one by one and apply some transformations to them.

It happens very often and I see a lot of junior or mid developers carry out this task using a classical iteration, with something like forEach, not knowing that there are better functions to solve this problem right in the Foundation framework.

Map

The map is a standard Swift function, used on a collection, that takes in input a closure to apply on every element and returns a different collection. In other words, you have a starting array, you take all the elements of the array one by one, apply on every single one of them a transformation ruled by your closure and append the resulting value on a new array.

Ok, let’s make an example. Let’s say we want to create a game where the player is given the anagrams of the names of Marvel heroes and he/she has to guess the right character. We have a list of names and we have to apply the next steps to every item of the list:

  1. Transform the names in lowercase
  2. Remove the whitespaces
  3. Shuffle the letters

Without map using a forEach for example you would need, for each step of course, to create an empty array, apply the step on each element and append the result… three arrays, too much stuff and quite hard to read and understand. Let’s see how verbose is this approach:

Using map instead everything is extremely easy and readable. It’s just like magic!

As you can see that’s extremely readable even if you don’t know all the steps involved.

CompactMap

CompactMap works similar to map but with a bonus… it removes every nil elements given by the transformation.

Let’s see a quick example:

As you can see, an emoticon cannot create a valid url. Using compactMap you can filter it without any problems or other checks.

CompactMap is also a great way to filter a list to remove any nil value. Recently I was working on an app where all the labels of the UI of one view controller were ruled by data sent by the server. If a value was there, you had to show the label, if not the label would be hidden without leaving a blank space.

Everything was dynamic in a UITableView so I only needed to add an item or not in the datsource (if you are interested in my personal technique to deal with datasources and sections take a look at this article).

Well, filtering everything with compactMap was super fast and super readable. Something like this, of course in the app was a bit more complicated:

Please note one thing in the latest example. The field array is of type [String?] while the items array is of type [String] so the returning type of compactMap is never an optional. Wow, amazing!

FlatMap

The last type of map is a function that, as the name says, flattens an array of arrays. It simply transforms a series of arrays into a single one in one pass, something like this:

[[1, 1, 1], [2, 2, 2], [3, 3, 3]] -> [1, 1, 1, 2, 2, 2, 3, 3, 3]

Let’s make an example.

You are coding one of those games with squads of fighting heroes. Your team has a group of characters and you decide who fights in each game.

In every round the number of enemies defeated is added to the stats of the playing hero. You now need to calculate the average number of defeated enemies per round of your squad, so basically you need to create a single array of all the stats of all the heroes and find out the mean value.

Let’s take a look at the code:

All the magic is done at line 25. Please note that I’ve used an extension to calculate the mean value ( line 26 ) instead of the vDSP.mean function ( link here ) of the Accelerate framework in order to keep the nice functional programming style.

One More Thing

If you read carefully at the beginning of the article, you may have noticed that I wrote about collections instead of simple arrays. Do you know why? Because the map functions could be applied to dictionaries as well! Any way to use those functions with dictionaries, extra care is needed:

As you can see from the example, the original dictionary is split into an array of dictionaries. Now, you may like to apply a transformation only to the values of the dictionary and not to the keys.

Well, you know what? Swift has a series of maps for all the three previous variants to accomplish this task! Simply use the mapValues version:

As you can see the result is a [String: String] and not a [[String: String]] like the previous example.

I hope you liked this article, if you did please clap it.
If this article was useful to you, feel free to offer me a coffee and and allow me to create more cool contents and articles.

Enjoy your coding!

Alessandro Manilii
Alessandro Manilii

Written by Alessandro Manilii

I’m an Italian professional iOS Developer, iOS Tech Lead at Wakala — Join Medium from the following link: https://medium.com/@alessandromanilii/membership

Write a response