Swift Functional Programming Tutorial
Learn how to program in Swift using functional programming techniques, such as map and reduce, in this Swift functional programming tutorial. By Colin Eberhardt.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Swift Functional Programming Tutorial
30 mins
The Magic Behind Filter
Swift arrays have a number of functional methods, such as map
, join
and reduce
. What, exactly, goes on behind the scenes in these methods?
It’s time to look behind the magic of filter and add your own implementation.
Within the same playground, add the following function:
func myFilter<T>(source: [T], predicate:(T) -> Bool) -> [T] {
var result = [T]()
for i in source {
if predicate(i) {
result.append(i)
}
}
return result
}
The above is a generic function that takes as its inputs a source, which is an array of type T
, and predicate
, a function that takes an instance of T
and returns a Bool
.
The implementation of myFilter
looks a lot like the imperative version you added at the start. The main difference is that you supply the condition being checked as a function rather than hard-code it.
Try out your newly added filter implementation by adding the following code:
evens = myFilter(Array(1...10)) { $0 % 2 == 0 }
println(evens)
Once again, the output is the same!
Challenge: The above filter function is global; why not see if you can make it a method on Array?
[spoiler title=”Hint 1″]You can add myFilter to Array via a class extension.[/spoiler]
[spoiler title=”Hint 2″]You can extend Array, but not Array<T>. This means that as you iterate over the items in the array via self, you’ll have to perform a cast.[/spoiler]
Reducing
The previous example was a simple one, making use of a single functional method. In this section, you’ll build upon the last, showing how you can implement more complex logic using functional techniques.
Create a new Swift playground and get ready for your next assignment!
Manual reduction
Your task in this section is just a little more complicated: Take the even numbers between 1 and 10 and compute their sum. This calls for what is known as a reduce function, which takes a set of inputs and generates a single output.
I’m sure you are more than capable of working this one out yourself, but here it is anyway! Add the following to your playground:
var evens = [Int]()
for i in 1...10 {
if i % 2 == 0 {
evens.append(i)
}
}
var evenSum = 0
for i in evens {
evenSum += i
}
println(evenSum)
The Assistant Editor will display the following result:
30
The imperative code above continues in the same vein as the previous example, adding an additional for-in
loop.
Let’s see what a functional equivalent looks like!
Functional Reduce
Add the following to your playground:
evenSum = Array(1...10)
.filter { (number) in number % 2 == 0 }
.reduce(0) { (total, number) in total + number }
println(evenSum)
You’ll see exactly the same result:
30
The previous section covered the array construction and use of filter
. The net result of these two operations is an array with five numbers, [2, 4, 6, 8, 10]
. The new step in the above code uses reduce
.
reduce
is a tremendously versatile Array
method that executes a function once for each element, accumulating the results.
To understand how reduce
works, it helps to look at its signature:
func reduce<U>(initial: U, combine: (U, T) -> U) -> U
The first parameter is the initial value, which is of type U
. In your current code, the initial value is 0
and is of type Int
(hence U
is Int
in this case). The second argument is the combine
function that is executed once for each element of the array.
combine
takes two arguments: the first, of type U
, is the result of the previous invocation of combine
; the second is the value of the array element that is being combined. The result returned by reduce
is the value returned by the last combine
invocation.
There’s a lot going on here, so let’s break it down step by step.
In your code, the first reduce iteration results in the following:
The inputs to combine are the initial value, 0, and the first item in the input array, which is 2. combine sums these values, returning 2.
The second iteration is illustrated below:
On the second iteration, the inputs to combine are the result from the previous iteration and the next item from the input array. Combining them results in 2 + 4 = 6.
Continuing this process for all the items in the array gives the following inputs and outputs:
The number highlighted in the bottom-right corner is the overall result.
This is quite a simple example; in practice, you can perform all kinds of interesting and powerful transformations with reduce. Below are a few quick examples.
Add the following to your playground:
let maxNumber = Array(1...10)
.reduce(0) { (total, number) in max(total, number) }
println(maxNumber)
This code uses reduce to find the maximum number in an array of integers. In this case, the result is rather obvious! Remember that here, total
is really just the result of max
of the last iteration of reduce
.
If you’re struggling to see how this works, why not create a table like the one above where you compute the inputs and output of combine
(i.e., the closure) for each iteration?
The examples you’ve seen so far all reduce arrays of integers into single integer values. Of course, reduce
has two type parameters, U
and T
, which can be different and certainly don’t have to be integers. This means you can reduce an array of one type into a completely different type.
Add the following to your playground:
let numbers = Array(1...10)
.reduce("numbers: ") {(total, number) in total + "\(number) "}
println(numbers)
This produces the following output:
numbers: 1 2 3 4 5 6 7 8 9 10
This example reduces an array of integers into the string shown above.
With a bit of practice, you’ll find yourself using reduce in all kinds of interesting and creative ways!
Challenge: See if you can use reduce to take an array of digits and convert them into an integer. Given the input array:
let digits = ["3", "1", "4", "1"]
Your reduce method should return an Int with the value 3141.