Higher Order functions in Swift
In mathematics and computer science, a higher-order function is a function that does at least one of the following:
– takes one or more functions as arguments (i.e. procedural parameters),
– returns a function as its result. -Wikipedia
Higher order functions are based on closures. These methods use closures to allow us to pass in functionality that can then determine how we want the method to sort, map, filter, or reduce an array of objects.
In this tutorial we will discuss about most commonly used higher order functions in Swift that are listed below:
- Map
- CompactMap
- FlatMap
- Filter
- Reduce
- ForEach
- Contains
- RemoveAll
- Sorted
- Split
In order to explain I’ll show you some of the examples of each of these methods and talk a little bit about how the syntax of the closure can change based on what swift can infer.
Map
Let’s get started with Map. This function performs an operation on all the elements of a collection and returns a new collection with the results of the operation on the original elements.
let digits= [2, 5, 3, 9, 15, 12, 8, 17, 20, 11]
let doubled = digits({ (digit) -> Int in
return digit * 2
})
Shorthand argument:
let doubled = digits.map { $0 * 2 }
We can use Map with Dictionary and Sets too.
var data = [String: String]()
data[“name”] = “John”
data[“place”] = “Austin”
data[“job”] = “QA”
data[“interest”] = “Singing”
let keys = data.map { $0.key } //Array of all keys
let values = data.map { $0.value } // Array of all values
let result = info.map { $0 } // Array of key and value pair
Compact Map
The major difference between map and compact map is the resulting array does not contain any nil values.
let digitsWithNil = [5, 15, nil, 3, 9, 12, nil, nil, 17, nil]
let notNilDoubled = digitsWithNil.compactMap { $0 != nil ? $0! * 2 : nil }
// Prints [10, 30, 6, 18, 24, 34]
Flat Map
It is useful when there are collections inside collections, and we want to merge them into one single collection.
let marks = [[3, 4, 5], [2, 5, 3], [1, 2, 2], [5, 5, 4], [3, 5, 3]]
let allMarks = marks.flatMap { (array) -> [Int] in
return array
}
Shorthand argument:
let allMarks = marks.flatMap { $0 }
// Prints [3, 4, 5, 2, 5, 3, 1, 2, 2, 5, 5, 4, 3, 5, 3]
If null values are available in the collection it will not remove and add null values as well.
Filter
Its purpose is to filter the elements of a collection based on a condition and produce a new one containing only those elements that satisfy the condition.
let digits = [2, 5, 3, 9, 15, 12, 8, 17, 20, 11]
let over10 = digits.filter { (digit) -> Bool in
return digit > 10
}
Shorthand argument:
let over10 = numbers.filter { $0 > 10 }
//Prints [15, 12, 17, 20, 11]
Reduce
The reduce function allows you to combine all the elements in an array and return an object of any type.
Notice that reduce has two parameters — initialResult and nextPartialResult. We need the initial result to tell us where to start, and the method then operates on that result based on the logic in the closure.
let digits = [5, 3, 8, 4, 2]
let product = digits.reduce(0, { $0 + $1 })
//Prints 22
For Each
Like all the other higher order functions, it provides a closure that implements the custom logic. But this time we’ll use the for Each function instead of using for-in :
let digits = [2, 5, 3, 9, 15]
digits.forEach { $0.isMultiple(of: 2) ? print(“\($0) is even”) : print(“\($0) is odd”) }
// Prints
2 is even
5 is odd
3 is odd
9 is odd
15 is odd
Contains
This function is used in collections in order to check if there are elements that satisfy a certain condition and it returns a boolean value.
let digits = [2, 5, 3, 9, 15]
let hasNumbersLessThan5 = digits.contains { $0 < 5 }
//Prints True
Remove All
Similar to contains
is the removeAll
method which is pretty handy when it’s necessary to remove collection elements based on conditions that regard the actual element values.
var digits = [2, 5, 3, 9, 15, 12, 8, 17, 20, 11]
numbers.removeAll { $0 < 10 }
//Prints [15, 12, 17, 20, 11]
Sorted
When sorting order must be specified (ascending or descending), or sorting should be based on a specific condition, then this is where sorted
higher order function gets into play.
let digits = [5, 3, 8, 2, 10]
let sorted = digits.sorted { $0 > $1 }
Even more shorthand argument:
let sorted = toSort.sorted(by: >)
//Prints [10,8,5,3,2]
Split
This function is used with String values and its purpose is to split a string into pieces based on a given condition. The result is an array of substrings. It works pretty similar to components(separatedBy:)
that breaks a string based on a given separator. Note though that in split
only characters can be provided as separators. You might wonder why this function applies on String values given that strings are not collections. The truth is that split
is used in the sequence of characters in the string, which conforms to the Collection
protocol.
Two more things to note. First, the type of the elements in the array that split
creates is String.SubSequence
, not String
. If you want to use them as strings, you must create string objects with them first. The following example creates a new array where all substrings are being converted to strings using the map
function:
let message = “Hello World!”
let result = message.split { $0 == “ “ }
print(result)
// Prints [“Hello”, “World!”]
// result type is [String.SubSequence]
// Create String values from substrings.
let allStrings = result.map { String($0) }
print(allStrings)
// Prints [“Hello”, “World!”]
// allStrings type is [String]
Reference: https://www.appcoda.com/higher-order-functions-swift/