What are the higher-order functions in Swift?


Throughout this tutorial, you will learn about the higher-order functions available in Swift. You will find out what they are used for and how to use them.

What are they?

A higher-order function is a function that takes one or more functions as arguments or returns a function as its result. Below are the higher-order functions provided by the Swift language −

  • forEach()

  • map()

  • compactMap()

  • flatMap()

  • filter()

  • reduce()

  • sort()

  • sorted()

All the higher-order functions are based on closure but don't worry you don't need to be a master of closure. They are easy to use and also reduce the size of the code in the project.

Why should you use them?

You can indeed do the same things without using higher-order functions. By utilizing higher-order functions in your code, however, you can avoid implementing functions that are already available in the Swift language in a very optimized manner.

Here we will look at all the functions with examples. Each will be discussed in detail with a practical example.

forEach()

It will iterate through all the elements in a collection (eg array) and not return anything. Remember that you cannot use continue and break inside the forEach function to exit the currently executing statement.

The ForEach function is similar to the for-in loop with a difference i.e. you cannot use continue and break statements in the forEach function.

Example

let numbersInWord = ["One", "Two", "Three", "Four", "Five", "Six"]
numbersInWord.forEach { 
   element in print(element)
}

Output

One
Two
Three
Four
Five
Six

Explanation

In the above example, you can see the forEach function iterating over all the elements. When you want an iteration over all the elements without breaking the execution flow, forEach() is best to use.

map()

The map function works by performing an operation on all the elements of a collection and returning a new collection with the results of that operation.

This function is designed to transform an object from one type to another type (as well as the same type).

Example 1

let numbers = [1, 2, 3, 4, 5, 6, 7]
let numbersInString = numbers.map { 
   number in String(number)
}
print("numbersInString: \(numbersInString)")

Output

numbersInString: ["1", "2", "3", "4", "5", "6", "7"]

Explanation

In the above example, you are converting each Int to a String using the map function. You can see how easy it is to map all the input elements.

Anyway, we can reduce this expression by using the shorthand argument $0, which refers to any element of the array. Below is an example −

Example 2

let lowercasedNumbers = ["one", "two", "three", "four"]
let uppercasedNumbers = lowercasedNumbers.map({ $0.uppercased() })
print("uppercasedNumbers: \(uppercasedNumbers)")

Output

uppercasedNumbers: ["ONE", "TWO", "THREE", "FOUR"]

Explanation

In the above example, we used $0 which represents the shorthand argument name to access the element inside the closure block. Here, $0 will give you the current argument's value.

compactMap()

Iterating through the elements in an array, compactMap() returns an updated array only containing elements that satisfy the condition stated within its body. The array will be updated without any elements that result in a nil value.

As a result, compactMap loops through all the elements in the array and returns non-nil values.

Example

let numbersInString = ["1", "x2", "3", "4", nil, "five5"]
let validNumbers = numbersInString.compactMap { 
    stringValue in
    Int(stringValue ?? "")
}
print("validNumbers: \(validNumbers)")

Output

validNumbers: [1, 3, 4]

Explanation

In the above example, the resulting array will not contain any nil values. The resultant array is guaranteed to have non-nil values.

flatMap()

The flatMap function allows us to transform a set of arrays into a single set that contains all of the elements.

Example

Here is an array that contains other arrays as elements. Suppose each inner array contains a student's marks for three different courses −

let marks = [[3, 4, 5], [2, 5, 3], [1, 2, 2], [5, 5, 4], [3, 5, 3]]

Now we have to combine all the marks and get the result into a single array.

We can perform a for-in loop and append all elements of each array to a result array. But why would you need to do it manually if you have a flatMap function provided by the Swift language? It takes less effort and is more optimized.

let marks = [[3, 4, 5], [2, 5, 3], [1, 2, 2], [5, 5, 4], [3, 5, 3]]
let allMarks = marks.flatMap { 
   marksArray -> [Int] in
   marksArray
}
print("allMarks: \(allMarks)")

Output

allMarks: [3, 4, 5, 2, 5, 3, 1, 2, 2, 5, 5, 4, 3, 5, 3]

filter()

The filter() will iterate through all elements in an array and will return an updated array only with the elements which satisfy the condition written inside the body of the filter.

In Swift, it is always an essential function. While you write code, many times you need to filter out collections to produce a filtered collection based on a condition.

The return type of the closure is a Bool value; items in the resulting array are those that satisfy the condition inside the body;

Example

let numbers = [-12, 23, -1, 56, 9, -2, 0, 14, 8]
let positives = numbers.filter { 
   number in
   number > 0
}
print("positives: \(positives)")

Output

positives: [23, 56, 9, 14, 8]

reduce()

The reduce function will iterate through all elements in an array and return an object with the combined value of all elements.

Example

let numbers = [1, 5, 2, 10, 6]
let sum = numbers.reduce(0) { 
   (result, number) -> Int in
   result + number
}
print("sum:", sum)

Output

sum: 24

Explanation

Above, the first argument is the result of the previous calculation that will be added to the number value. You can understand the logic behind the reduce function as follows −

// 1st iteration: result = 0, number = 1, Return 1
// 2nd iteration: result = 1, number = 5, Return 6
// 3rd iteration: result = 6, number = 2, Return 8
// 4th iteration: result = 8, number = 10, Return 18
// 5th iteration: result = 18, number = 6, Return 24

sort() & sorted()

The sort function will sort all elements according to the condition written inside the body of the closure.

The sorted function will sort all elements according to the condition written inside the body of the closure and return a new sorted array.

sort()

Example

var numbers = [1, 5, 2, 10, 6]
numbers.sort()
print("Sorted numbers: \(numbers)")

Output

Sorted numbers: [1, 2, 5, 6, 10]

Explanation

In the above example, we initialised a variable that contains unsorted numbers. We have to sort them without using any other variable or constant. In that case, we use the sort() function which sorting elements within the same variable.

Note here, we can use sort() on a variable, not on a constant because sort() uses the same variable to sort the elements.

sorted()

Example

let numbers = [1, 5, 2, 10, 6]
let sortedArray = numbers.sorted()
print("sortedArray:", sortedArray)

Output

sortedArray: [1, 2, 5, 6, 10]

Explanation

This function sorts the elements and returns a new sorted array.

Conclusion

This article demonstrated how to use higher-order functions in Swift. You are now confident enough to use them in your code. Make sure you learn more about them and do some practical examples.

Updated on: 09-Dec-2022

5K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements