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.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

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:

Iteration1

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:

Iteration2

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:

Iteration3

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.

Colin Eberhardt

Contributors

Colin Eberhardt

Author

Over 300 content creators. Join our team.