Higher order functions in Swift: Filter, Map, Reduce, flatmap, compactMap

Ever since I learned about functions and closures in detail, I wanted to know more about the advantages and usages of these in programming. I read about higher order functions that can be used on collection types and this is what I understood.

I don’t know who that is over there at the top.

As far as I understood, higher order functions are functions that takes another function/closure as argument and returns it.

I will try to explain this first. Consider the following code which will give you an idea what a higher order function is :

higher order functions in swift

The first two methods are of type (Double,Double)->Double . First one accepts two double values and return their sum . The second one returns the product of these two double values. The third method is a higher order function which accepts three parameters. Two double values and a function of type (Double,Double)->Double . Do have a look at the method call. You will understand how a higher order function works.

Here , the function doArithmeticOperation(isMultiply:) is a higher order function which returns a function of type (Double,Double)->Double .

Functions and closures are first class members in swift. They can be saved into a variable and passed around.

So, here , based on the bool value passed into the doArithmeticOperation(isMultiply:) function, it returns the function which does the operation.

operationToPerform_1 is a function that does the multiplication for you.

operationToPerform_2 is a function that does the addition for you.

Just have a look at the function definition and call. You will understand everything.

Of course, you can do the same stuff in plenty of different ways. May be you could use a closure instead of functions. You could create an enum of arithmetic operations and simplify the function. I just meant to explain what s higher order function is .

Here are some of the higher order function used in swift. If I understood correctly, the following functions uses closures as argument . You can use these functions to operate on Swift collection types such as Array, setor Dictionary .

You should understand what a closure is before going through the following. Read my article on closures

Map

Use map to loop over a collection and apply the same operation to each element in the collection. The map function returns an array containing the results of applying a mapping or transform function to each item.

Suppose we have an array of integers:

What if we have to multiply every number by 10 ? We normally use a for-in loop to iterate through every number and do the operation right?

This code looks verbose. There are some boilerplate code like creating a new array, which could be avoided using map. The swift autocomplete shows the following if we try to map the Int array.

maps on int array

The closure transform accepts an int argument and returns a generic type.

This is the shortest version of using map on an array of Int. I used the shorthand syntax of closures using $ operator.

All the following code will work the same as above , but a complex to simplified syntax. You should have a good knowledge in closures to do that.

simplifying the map closure syntax

Working of map: The map function has a single argument which is a closure (a function) that it calls as it loops over the collection. This closure takes the element from the collection as an argument and returns a result. The map function returns these results in an array.

Consider a dictionary with book names as key and the amount of each book as the value.

If you try to do a map function on a dictionary, the swift autocomplete will look like this:

map on dictionary

Here, for the above dictionary, as we iterate over the collection our closure has arguments that are a String and a Double from the types of the key and value that make up each element of the dictionary. The return type can be an array of uppercased keys, values array with discounts or even an array of tuples. It’s all upto you.

map on dictionary return values

Note: The return type of a map function is always a generic array. You can return an array of any type.

In this case we have a set containing elements of type Double so our closure also expects a Double. lengthInMeters is a set. lengthInFeet is an array.

What if you want to know the index of the collection while applying map to it??

Answer is simple. You will have to enumerate it before mapping.

Check the code below.

Filter

Use filter to loop over a collection and return an Array containing only those elements that match an include condition.

Consider the following code to filter even numbers from an array of integers.

filter using for-in loop

Now, like map , there is a simple method to do the filtering stuff for collection types.

The swift autocomplete shows the following if we try to use filter method for an Int array.

As you can see, the filter function calls a closure called isIncluded which takes one int as argument and returns a Bool . So, the isIncluded closure will return a bool value for each collection item and based on this result a new filtered array will be generated.

The filter method has a single argument that specifies the include condition. This is a closure that takes as an argument the element from the collection and must return a Bool indicating if the item should be included in the result.

filter an int array

The filter closure can be further simplified like we did for map.

Simplified filter closure on Int array

Consider a dictionary with book names as key and the amount of each book as the value.

If you try to do a filter function on a dictionary, the swift autocomplete will look like this:

filter autocomplete on dictionary

The filter functions will call a closure called isIncluded by passing each key-value pair and do the condition check (here, it accepts a String and Double as arguments). Finally, based on the bool value returned, the filter function will decide whether or not to add the key-value pair in the returned array.

Important: Filter function on dictionary returns an array of Tuples as you can see in the playground code below:

This can be further simplified as:

$0 is the key, $1 is the value

filter on set

Here, the filter closure for set takes a Double argument and returns a Bool for each element in the set. Based on this Bool value, the item is included in the filtered array.

IMPORTANT: The return type is a filtered array.

Reduce

Use reduce to combine all items in a collection to create a single new value.

Declaration as in apple docs:

So, the reduce function takes two arguments.

  • One is an initial value which is used to store the initial value or the value or result returned by the closure from each iteration.
  • The other one is a closure which takes two arguments, one is the initial value or the result from the previous execution of the closure and the other one is the next item in the collection.

Let’s understand this with an example:

Check the following array of numbers.

reduce method on arrays

This reduce function will iterate four times.

  1. Initial value is 0, x is 0, y is 1 → returns x+y . So, initial value or Result becomes 1.
  2. Initial value or Result is 1, x is 1, y is 2 → returns x+y . So, initial value or Result becomes 3 .
  3. Initial value or Result is 3, x is 3, y is 3→ returns x+y . So, initial value or Result becomes 6.
  4. Initial value or Result is 6, x is 6, y is 4→ returns x+y . So, initial value or Result becomes 10

The reduce function can also be simplified like:

reducing on int array

Here the closure is of type (Int,Int)->Int . So, we can pass any function or closure of type (Int,Int)->Int . In this scenario, instead of the closure, we could also pass basic operator functions like +, -, *, / .

We can also use multiplication or other operation or logic inside the closure.

the above line can also be written as:

Reduce will also work with strings using the + operator to concatenate:

Let’s reduce the bookAmount Dictionary:

reducing dictionary

For dictionary, the closure inside the reduce function takes two arguments.

  1. An initial or result value of the type that should be reduced to.
  2. A tuple of current key-value pair.

The reducedBookNamesOnDict2 can be further simplified using the short closure syntax like:

The reduce on set works the same way as in arrays.

Return type is the return type of closure. Here it is Double.

Flatmap

Flatmap is used to flatten a collection of collections . But before flattening the collection, we can apply map to each elements.

Apple docs says: Returns an array containing the concatenated results of calling the given transformation with each element of this sequence.

(fig — 1) Read the above definition and have a look at this code.
(fig — 2)… and this (string is a collection from swift 4).

In the (fig — 2) above, the flatMap iterates through all the collections in the collection called codes. Here, the individual collections are string (string is a collection from swift 4). Here are the steps:

1 . Apply upperCased() function to all strings. This is similar to

Output will be:

2 . Flatten all the sub — collections to one single collection.

Finally, this is what flatMap does to a string

Tip:

In swift 3, flatmap was also used for removing nil values from a collection. This is deprecated now and the complier will throw a warning when used.

We should use compactMap instead. Explained later in this article.

I think, now it is clear what a flatMap does.

flatmap of array of array of int

It returns an array of tuples after flatmapping. We have to convert it to an array:

flatmap an array of dictionaries
flatmap on set

Advantages of flatmap:

Let’s dig into the advantages of flatmap:

Even more usefully it knows about optionals and will remove them from a collection.

flatmap to remove optionals.

We can apply flatmap on collection of collections. ie; an array of arrays will be flattened to a single array. So, the flatmap closure takes a single collection of argument, do something with this collection and /or return the collection. Here , before returning the collection, we can apply filter or map or even reduce.

filtering while flatmap

When applying the short closure syntax:

Chaining : (map + filter + reduce)

We can chain multiple higher order functions one by one.

You can read my article on chaining methods to understand its working.

The working principle behind the chaining is simple. The map and filter methods act on a collection and returns another collection . And now, we can again apply another higher order function on this collection. It’s that simple.

Let’s say we want to add the squares of all the even numbers from an array of arrays.

add the squares of all the even numbers from an array of arrays.

CompactMap

Returns an array containing the non-nil results of calling the given transformation with each element of this sequence.

If you do compactmap a collection containing optional values, it will only consider the non-nil values. This doesn’t do anything on sets and dictionaries as Sets cannot have nil values and for dictionary, the compactmap will give an array of tuples with key and value.

Note: In swift 5, compactMapValues() is introduced which adds functionality to dictionary as well. Will update the article soon.

compactmap on dictionary

The output of map became a collection of optional int ([Int?]) only because the array had nil — value in it. Otherwise it would have been an Int array.

Conclusion

Well, thats it!! You mastered Higher order functions!!

Use Higher order functions where ever possible:

  • It improves your swift skills.
  • Enhances readability of code.
  • More functional programming.

Our objective is to write less code which makes more sense!!!

Enjoy!!

Reference: Link1

You can follow me on Medium for fresh articles. Also, connect with me on LinkedIn and Twitter.

If you have any comment, question, or recommendation, feel free to post them in the comment section below!

iOS and tvOS developer, dreamer, photographer 🤨

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store