# FlatMap And CompactMap Explained In Swift Swift has a bunch of functions that are useful for transforming collections and sequences. In this article, we’ll discuss `map(_:)`, `flatMap(_:)` and `compactMap(_:)`.

In a previous article, we’ve discussed how you can use `filter(_:)` and `reduce(_:)`. These higher-order functions are super helpful for transforming collections, in a concise and insightful way.

If you’re not familiar with closures, make sure to read up on them first: The Ultimate Guide To Closures In Swift.

## How To Use map(_:)

Our starting point is the `map(_:)` function. This function applies a transformation to each of the elements in a sequence. Here’s an example:

Let’s break that down:

First, we’re creating an array `numbers` with a few integer values. Then, the function `map(_:)` is called on `numbers` and its result is assigned to `result`.

The `map(_:)` function has one parameter, a closure, which returns the result of `\$0 * \$0`. The `\$0` corresponds to the first parameter of the closure, i.e. the number from `numbers` that’s being transformed.

In essence, the operation `\$0 * \$0` is called on every number in `numbers`, and the resulting array is assigned to `result`. You’re transforming – or “mapping” – one array into another. You’re calculating the square of every number.

Transforming an array with `map(_:)` is similar to using a for loop, but much more concise. Like this:

``````let numbers = [2, 3, 4, 5]
var result = [Int]()

for number in numbers {
result += [number * number]
}

print(result)
``````

Here’s another way to look at it. With `map(_:)`, the input array of numbers is transformed into another array of numbers. Like this:

``````2 => 2 * 2 => 4
3 => 3 * 3 => 9
4 => 4 * 4 => 16
5 => 5 * 5 => 25
``````

Functions like `map(_:)` are called higher-order functions, because they take a function as input – as opposed to ordinary values. Higher-order functions can also output functions, which is useful for a programming paradigm called functional programming.

Technically, you can call higher-order functions like `map(_:)` on any sequence. This includes collections like arrays, dictionaries, and sets, ranges like `1...100` and so-called iterators. Anything that looks like a “list” of values, basically.

We’ll discuss why higher-order functions are useful at the end of this article. Let’s first move on to learn about `flatMap(_:)` and `compactMap(_:)`.

#### Become a professionaliOS developer

##### Get started with iOS 13 and Swift 5

Sign up for my iOS development course to learn iOS development with Swift 5, and start your professional iOS career.

## How To Use flatMap(_:)

The `flatMap(_:)` function is similar to `map(_:)` except that it “flattens” the resulting array. Here’s an example:

The above code starts out with a nested array of integers. The `numbers` array consists of an array of 3 arrays, that each contains 3 numbers.

The closure `{ \$0 }` simply returns the first argument of the closure, i.e. the individual nested arrays. When you call `flatMap(_:)` on the `numbers` array, you end up with a flattened array of individual numbers.

Let’s look at another example. Imagine you’re working with 4 groups of giraffes, and want to create one single group of giraffes that are taller than a certain height. Here’s how you do that:

In the above code, the function `filter(_:)` is called on every nested array inside `giraffes`. We only want integers that are greater than `10`. The resulting arrays are flattened, and assigned to `tallest`.

Consider what would happen if we had used `map(_:)` instead of `flatMap(_:)`. The resulting array wouldn’t be flattened, like this:

``````[[], [11, 13, 20], ]
``````

The `flatMap(_:)` function calls `map(_:)` on the array items first, and then flattens it. That’s why something like the following doesn’t work:

``````let numbers = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let result = numbers.flatMap({ \$0 * 2 })
``````

In the above code, the `\$0` refers to the arrays inside numbers. Multiplying an array by two is impossible, so that’s why this code doesn’t work.

It’s smart to think about flatmapping as seeing an array in one less dimension. You start with a two-dimensional array, and end up with a one-dimensional array after `flatMap(_:)`.

What about using `flatMap(_:)` with optionals? Let’s look at that next.

The name “compact map” is based on the idea that removing `nil` items from an array makes the array more compact. Likewise, the name “flat map” comes from flattening the array. And “mapping” is a concept from mathematics, where you associate the values in one set with another set.

## How To Use compactMap(_:)

Before Swift 4.1, `flatMap(_:)` could also be used to filter out `nil` values from flattened arrays. Since Swift 4.1+, you now use the explicit `compactMap(_:)` for this purpose.

Here’s an example:

See what happens? The most important part of the code is `Int(\$0)`. This takes an individual string from `numbers` with `\$0` and attempts to convert to an integer, with the `Int()` initializer.

This `Int()` initializer can return `nil` – it’s an optional – so its return type is `Int?`. As a result, the return type of the mapping transformation is `[Int?]` – an array of optional integers.

``````[Optional(5), Optional(42), nil, Optional(100), nil]
``````

However, `compactMap(_:)` automatically removes `nil` elements from the returned array. And as such, it’s return type is non-optional.

``````[5, 42, 100]
``````

In the above code, the type of `result` is `[Int]`. If you would have used `map(_:)`, the return type would have been `[Int?]`. And you would have needed an extra step to unwrap the values from the array, to work with them.

## Why Use These Higher-Order Functions?

Working with `map(_:)`, `flatMap(_:)` and `compactMap(_:)` in the abstract makes it sometimes hard to imagine their practical use cases. Let’s discuss why you’d want to use them.

Using functions like `map(_:)` to apply transformations to sequences has a few advantages:

• It’s more concise than using a `for` loop, because you don’t need temporary variables and a multi-line `for in { }` block.
• You can typically write a call to `map(_:)` on one line, which (usually) makes your code more readable.
• Functions like `map(_:)` can be chained, so you can apply multiple transformations to a sequence one by one.

In general, higher-order functions are useful because they let you apply a function to a sequence of values. Instead of coding the transformation procedurally, you can just apply the function and get a result back.

The most practical use case for `flatMap(_:)` is working with input values that are grouped, or nested, but the output value you want needs to be one-dimensional.

A practical use case for `compactMap(_:)` is working with a transformation that can return `nil`. You save yourself a few trivial steps by letting `compactMap(_:)` filter out `nil` values immediately.

Imagine you’re building a social media app. You want to construct a timeline of posts for a user. You use 3 queries to select post IDs for the user, for instance from follower posts, advertisements, and trending topics.

• You can use `map(_:)` to expand these IDs into actual `Post` objects
• You can use `flatMap(_:)` to flatten the 3 groups into one collection
• You can use `compactMap(_:)` to discard posts that couldn’t be expanded

#### Become a professionaliOS developer

##### Get started with iOS 13 and Swift 5

Sign up for my iOS development course to learn iOS development with Swift 5, and start your professional iOS career.

It’s worthwhile to learn about `map(_:)`, `flatMap(_:)` and `compactMap(_:)`, because they make your code more concise and readable. You can add more functional programming to your app’s code. Once you get used to them, you can’t believe you could do without them.

Especially the differences between `map(_:)`, `flatMap(_:)` and `compactMap(_:)` are worth pointing out. The first one applies a transformation to a sequence, the second one flattens the resulting array, and the third one removes `nil` values before returning its result. Awesome! 