Higher Order Functions in Swift - map()
I've decided to cover the most used higher-order functions in Swift and I will be writing a high-level overview of each one with a few examples to better understand them.
What is a high-order function?
Higher-order functions are used a lot in functional programming. They are functions that take other functions as arguments or return functions as return values, or both. You'll probably be familiar with map, filter, and reduce, which are higher-order functions. In this post, I will be going throw the map function and how to use it.
map()
The map function is probably the most famous higher-order function. 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.
How does it work? Let’s say we have an array of numbers like this one :
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Assume you want to create an array that will contain the numbers above but multiplied by two. The traditional way to do this will be using a for-loop like this:
var doubled = [Int]() for number in numbers { doubled.append(number * 2) } print(doubled) // Prints [2, 4, 6, 8, 10, 12, 14, 16, 18, 20])
First, we are initializing an array with the same type as the numbers array then we loop through the numbers array, and in each iteration, we multiply the number by two and append it to the doubled array then we print it. Easy and basic and defiantly can be written more neatly.
Now, let’s try to use map to do the same task. In Xcode start typing the following:
doubled = numbers.map
Xcode will auto-suggest the map function, press return and you should see this:
doubled = numbers.map(transform: (Int) throws -> T)
Pressing return again will tell Xcode to replace the placeholder and provide you with the default implementation like this:
doubled = numbers.map({ Int in <code> })
The first thing to look at here is the closure where we’ll add the implementation of the operations we want to perform to the original data. It takes an argument, which represents a single element in the original collection. In this example, that argument represents a number in the numbers array, The in keyword indicates that the definition of the closure's parameter and return type has finished, and the body of the closure is about to begin. Higher-order functions iterate on collections, so that argument will represent all items on them sequentially. Meaning in the first iteration this argument will be equal to 2 which is the first number in the numbers array, in the second iteration this argument will be equal to 5, and so forth.
Then, there’s a generic return type T, which has to become specific. This is the type of data the closure will return; we will return Int values here.
So to start using map let’s set an argument name to the placeholder, and change the return type to Int:
doubled = numbers.map({ (number) -> Int in })
Map function returns a new collection. So to use it, we need a collection of the same type as our array. What we are missing now is our logic. What we want is to do is to multiply the number parameter by 2 so we write this:
var doubled = [Int]() doubled = numbers.map({ (number) -> Int in return number * 2 }) print(doubled) // Prints [2, 4, 6, 8, 10, 12, 14, 16, 18, 20])
That's it. It's as simple as that. One more thing. the above use of the map function is totally correct, however, we can make it even shorter! How? By avoiding the full definition of the closure with an argument and return value, and by making use of the shorthand argument:
let doubled = numbers.map { $0 * 2 } print(doubled) // Prints [2, 4, 6, 8, 10, 12, 14, 16, 18, 20])
What is this $0?
$0 is called a shorthand argument, and it’s a way to refer to any element in the source collection. In this case, it represents any number in the numbers array, the same as the number parameter in the previous example of map. Also, notice that the opening and closing parentheses of the method have been omitted. if we print doubled array we get once more the exact same results as the first two times. But this time it took us just one line of code to do it.
Use map() with Other Data Types
You can call the map() function on a dictionary too. Just remember that the map() function always returns an array. Even though dictionaries need a slightly different approach depending on whether we want to get just keys, just values, or both.
map function returns an array of values, so getting only keys or values is easy. For instance:
let data = [ "name": "ahmed", "address": "cairo", "college": "mansoura university" ] let keys = data.map { $0.key } let values = data.map { $0.value } print("keys: \(keys)") print("values: \(values)") // keys: ["name", "address", "college"] // values: ["ahmed", "cairo", "mansoura university"]
If you tried to do this:
let result = data.map { $0 }
That will print out a tuple, That is why you can use the key and value accessors to refer to keys and values in the dictionary. Each element of the result array is a tuple where the first value is the key, and the second is the actual value matching the key.
print(result) // [(key: "name", value: "ahmed"), (key: "address", value: "cairo"), (key: "college", value: "mansoura university") keys: ["name", "address", "college"]]
Acting on both keys and values now is very easy. For example this how would we convert keys to uppercased strings, and to capitalize the first letter of each value:
let uppercasedkeys = data.map { $0.key.uppercased() } let capitalizedvalues = data.map { $0.value.capitalized }} print("uppercased keys: \(uppercasedkeys)") print("capitalized values: \(capitalizedvalues)") // uppercased keys: ["COLLEGE", "ADDRESS", "NAME"] // capitalized values: ["Mansoura University", "Cairo", "Ahmed"]
Higher-order functions will make your life much easier as a programmer if you understand how it works, I hope I made it at least a little easier for you if you have any questions please let me know.
iOS Developer
3yماشاء الله ربنا يكرمك ياناجي ويزيدك ♥️
Senior Business Analyst at STC | Aspiring Solution Architect | AWS Professional SA Training Alum | Apple Developer Academy Graduate | Co-founder | Digital Transformation & Innovation Leader
3yThanks for sharing
iOS Engineer || SWE @ Extend | The Ad Network. | ITI Graduate
3yVery useful bro ♥️
Senior iOS Engineer @Convertedin
3ywow appreciated effort ماشاءالله ❤️
iOS Developer @Nexta
3yGreat work keep going bro ❤️