Swift Higher Order Functions
Let’s examine Higher Order Functions in Swift Programming Language. Higher Order Functions are basically generic functions on Swift Standart Template Library to handle some processes on Collections with easier way to use.
Map
Map is the one of the best known higher-order function. Let’s start with the description of it.
func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]
As you can see, it’s generic and there is an callback to transform Element
to T type. T
can be anything.
For example, in a scenario, you have an array of celcius
degrees and you have to convert it them to Kelvin
so basically you can write a for-loop like below.
# MARK: - formula: T(K) = T(°C) + 273
var celciusArray = [10,20,30,-10,45]
var kelvinArray: [Int] = [Int]()
for celciusItem in celciusArray {
kelvinArray.append(celciusItem + 273)
}
As you see this is so complicated to write. Imagine this you can convert it in a single line. You can achieve it with map(_ :)
function.
# MARK: - formula: T(K) = T(°C) + 273
var celciusArray = [10,20,30,-10,45]
var kelvinArray = celciusArray.map { $0 + 273 }
This is as easy as possible scenario and in Swift world you can see map everywhere.
The time complexity of the map is O(n)
because of its looked at all of the element of the collection / sequence.
Filter
Filter is one of the best functionalities for filtering an collection type. As you can see below, the definition of the **filter(_ :)** function.
func filter(_ isIncluded: (Self.Element) throws -> Bool) rethrows -> [Self.Element]
When you use filter, you have to describe the isIncluded conditions. In callback of filter, will be filtered any item which returns true from the checking conditions.
For example, you have an struct named as Plane
struct Plane{
var model: String
var maxAltitude: Int
}
var planeArray = [
Plane(model: "Airbus", maxAltitude: 1000),
Plane(model: "Boeing", maxAltitude: 2000),
Plane(model: "Airbus", maxAltitude: 3000),
Plane(model: "Boeing", maxAltitude: 4000),
Plane(model: "Airbus", maxAltitude: 5000),
Plane(model: "Boeing", maxAltitude: 6000),
]
Maybe you want to filter the planeArray
with just maxAltitude
is bigger than 3500. With filter(_ :)
function you can achive just like this.
let filteredArray = planeArray.filter{ $0.maxAltitude > 3500 }
The filteredArray will contains only Plane instances with maxAltitude > 3500. Just simple as it looks.
The time complexity of the map is O(n)
because of it will be travel all elements of the Collection
for filter.
Reduce
reduce(_: _:)
Reduce in Swift language returns the result of the closure which let you combine elements in the Collection
. The function definition is in below.
func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
initialResult
is the value of the combining initial value. Because of the reduce(_:, _:)
function is generic, the initialValue
type must be the same type with nextPartialResult
. nextPartialResult
returns the value of the closure which you can handle it. If you return a string from an array, you set initialResult
a String
and the result of the nextPartialResult
closure must return String
or if same scenario with start Int
you must return Int
from the nextPartialResult
closure.
Let’s give an example to return a String
from a Int
collection.
let integers = [1,2,3,4,5]
let result = integers.reduce("Numbers are : ", { "\($0)" + " - " + "\($1)" })
The result array will return “Numbers are 1 - 2 - 3 - 4 - 5”
And maybe you may want to sum the array of Int
.
let integers = [1,2,3,4,5]
let result = integers.reduce(0, { $0 + $1 })
The result will be the sum of the array.
The complexity of the Reduce is O(n)
because it has a loop over the Collection which it’s used from index 0 to index N(lenght of collection).
FlatMap
FlatMap is a generic function
func flatMap<SegmentOfResult>(_ transform: (Self.Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
In Apple documentation flatMap described with this sentence; Returns an array containing the concatenated results of calling the given transformation with each element of this sequence. As it described flatMap convert list of lists to single list structure.
For example you have an array like below
let tryIt = [[1,2,3],[4,5]]
print("flat map result > ", tryIt.flatMap{$0})
# flat map result > [1, 2, 3, 4, 5]
As you can see above, the list of list structure mapped to the single list structure via help of flatMap
. And you have to learn another key thing of the flatMap
. It contains nil
values too. For example you have an array like below
let tryIt = [[1,2,3],[4,5,nil]]
print("flat map result > ", tryIt.flatMap{$0})
# flat map result > [Optional(1), Optional(2), Optional(3), Optional(4), Optional(5), nil]
As you can see the result is single list structure but every value is Optional
. Why? Because flatMap checks the collection is contains any Optional
or not? If it contains optional, the result will be type of Optional
. That’s it. But Apple
recommends that when you work with a collection contains Optional
you better use CompactMap
rather than flatMap
.
The complexity of the flatMap is O(N + M) where N is the source collection size and M is the result array size.
CompactMap
CompactMap as same as flatMap
but with a difference. If a collection contains nil
then it can be better to use CompactMap
.
var singleList = [1,2,nil,4]
print("FLAT > ", singleList.flatMap({$0}))
print("COMPACT > ", singleList.compactMap({$0}))
# FLAT > [1,2,4]
# COMPACT > [1,2,4]
It seem same but flatMap deprecated in Optional sequences. So you better to use compactMap
.
flatMap & compactMap
Let’s create a scenario to use them together. You have an array of arrays which contains nil
.
let tryIt = [[1,2,3],[4,5,nil]]
let flatResult = tryIt.flatMap{$0}
// flatResult = [Optional(1), Optional(2), Optional(3), Optional(4), Optional(5), nil]
let compactResult = flatResult.compactMap{$0}
// compactResult = [1, 2, 3, 4, 5]
/*
or you can just chain them with single line tryIt.flatMap{$0}.compactMap{$0}
*/
As you see, it’s good to use in different scenarios to handle collections in many way.
I hope you like the article.
Happy coding 🧑💻 🎮