Swift, like many modern languages, has implemented some beautiful, functional capabilities to its core. If you are not experienced with the functional paradigm, it's common to implement the classic for-loop for resolving the frequently seen problems around collection types, but that's not the Swiftiest way. So today, I'm going to introduce High Order Functions, which will let you simplify your code when a collection type joins in.
A Higher-Order Function is a function that receives other functions as arguments or a function that returns another function as its result. We'll be using Map, Reduce, and Filter in this post. Let's get started!
Map
In many programming languages, map is the name of a higher-order function that applies a given function to each element of a functor, e.g. a list, returning a list of results in the same order.
Source: Wikipedia
Instead of writing a for loop and applying your business logic to each element, the map function takes care of that for you. It's only necessary to code the function that will be used to each element, saving us time and lines.
For example:
let array = [1, 2, 3, 4, 5, 6, 8] | |
//sums 1 to each element | |
var mappedArray = array.map({ | |
(value: Int) -> Int in | |
return value + 1 | |
}) //it iterates and applys this closure to every item in the array | |
//more simplified | |
mappedArray = array.map { e in | |
return e+1 | |
} | |
//even more simplified | |
mappedArray = array.map { $0 + 1} | |
// mappedArray-> [2, 3, 4, 5, 6, 7, 9] |
Also you are able to transform your collection to another collection with a different type.
let array = [1, 2, 3, 4, 5, 6, 8] | |
//convert the Array<Int> to Array<String> | |
var mappedArray = array.map({ | |
(value: Int) -> String in | |
return String(value) | |
}) //it iterates and applys this closure to every item in the array | |
//more simplified | |
mappedArray = array.map { e in | |
return String(e) | |
} | |
//even more simplified | |
mappedArray = array.map { String($0) } //return an array of strings | |
//mappedArray -> ["1", "2", "3", "4", "5", "6", "8"] |
Filter
In functional programming, filter is a higher-order function that processes a data structure (usually a list) in some order to produce a new data structure containing exactly those elements of the original data structure for which a given predicate returns the boolean value true.
Source: Wikipedia
The filter function iterates over a collection and then returns a new array containing those elements that have matched our predicate condition.
//returns a new array only with even numbers | |
var filteredArray = array.filter({ | |
(isIncluded: Int) -> Bool in | |
return isIncluded%2==0 | |
}) | |
//more simplified | |
filteredArray = array.filter { e in | |
return e%2==0 | |
} | |
//even more simplified | |
filteredArray = array.filter { $0%2==0 } |
Reduce
In functional programming, fold (also termed reduce, accumulate, aggregate, compress, or inject) refers to a family of higher-order functions that analyze a recursive data structure and through use of a given combining operation, recombine the results of recursively processing its constituent parts, building up a return value.
Source: Wikipedia
Okay, that sounds too technical. Let me explain it in other words. What reduce function does is to combine every item of a collection in a unique value.
let array = [1,2,3,4,5,6] | |
//starting on zero, sum every element to the result | |
var reducedValue = array.reduce(0) { (result, e) -> Int in | |
//initially result is zero | |
return result + e | |
} //returns 12 | |
//simplified | |
reducedValue = array.reduce(0, +) //12 |
Let's see all of these together in action. Do you remember my previous post where I was introducing a new way to solve a common problem? Now let's do that again but using what we just learned.
So, now instead of using the classic for-loop like this:
extension Array where Element == Piece { | |
var totalPrice: Double { | |
var x = 0.0 | |
self.forEach { piece in | |
if piece.selected { x+=piece.price} | |
} | |
return x | |
} | |
} | |
let pieces = [Piece]() | |
let stringArray = [String]() | |
print(pieces.totalPrice) //prints the total price of selected pieces | |
print(stringArray.totalPrice) //throws Value of type '[String]' has no member 'totalPrice' |
We could just reduce this to a one single line:
extension Array where Element == Piece { | |
var totalPrice: Double { | |
//YES, you can combine them | |
return self.filter { $0.selected }.map { Double($0.totalPrice) }.reduce(0.0, +) | |
} | |
} |
It's now more elegant than before.
Top comments (0)