Use Swift’s reduce function to get unique values from a collection

Recently I needed a Swifty way to get some Core Data records into an array with other arrays. After a search on Stackoverflow I learned that using the ‘reduce’ function was the way to go. Because I tend to forget how the function works, I decided to write it down for future me. Maybe it is also useful for you.

The thing to remember about the reduce function is that it is called on a collection type and it takes two arguments:
– An initial value; and
– A closure in which something is done with the initial value and the elements of the collection.

On the first iteration, the closure combines the initial value and the first element of the collection. After that, the combined value is combined with the second element of the collection. This goes on until the sequence is exhausted. Then, the last combined value is returned. Take a look at the next illustration:

Illustration for reduce function Swift

This example begins with an Integer value of 21. The closure then adds the first value of the array, which is 5. The partial result is 26. On the next iteration it combines the partial result (26) with the next value in the array, which is 6. So, the next value is 26 + 6 = 32. This goes on until all the elements of the array are added. The result is 58. In code this looks like this:

We could also write it more shorter using the placeholders:

Or, if you want to go very concise, write it like this:

An interesting quality of the reduce function is that the initial value and the end result can be another collection type, like an array or a dictionary. Take a look at the next illustration:

Illustration for Swift reduce function

In this example, the reduce function is used to filter out duplicates. It returns a new array with unique values only. Here, the initial value isn’t an Integer, but an empty array which could hold values of any type. On the first iteration, the closure decides whether the first element of the collection (which is 5) is in the initial value array. Of course it isn’t because this array was empty to begin with. So, the first element (5) is added to the array. Then, on the next iterations 6, 9 and 7 are added so the initial value array now holds 5, 6, 9 and 7. But then it stumbles upon another 6, which is already in the array. The closures just returns the initial value array without adding the new 6 element to it. It moves on, and on the last iteration the 4 is also added. The result is an array that holds 5, 6, 9, 7 and 4. In code this looks like this:

Or, more concise:

It’s also possible to use the reduce function to convert a collection to another (custom) data structure. Let’s take a look at the following example:

We declare a custom type called Visitor, which is a struct holding two variables: name and yearOfVisit. To be able to use the reduce function we need to conform to the Equatable protocol, otherwise the combine closure can’t compare both arguments in the closure. Conforming to this protocol simply means that we have to implement a type method called ‘==’ which returns a Bool. In the implementation of this function we decide what counts as equal. In this case, two instances of Visitor are equal if both the name and the yearOfVisit are equal.

We also declared an array that holds 12 visitors. As you might have noticed, there are two duplicate records: v1 & v11 are equal. The same goes for v3 & v12. We can filter those duplicates out with the reduce function we already used above:

Now we have a new array without any duplicates. Wouldn’t it be nice that we would have a collection that we could easily query for specific information? Like: who visited in 2014? How many visitors were there in 2012? Which years are in the database? Etc.

To reach our goal, we could use the following code:

In this case, the initial value that give the reduce function is an empty dictionary with and Int as the key and an array of Visitor objects as the value. The key value for the dictionary will be the yearOfVisit. For each iteration, the combine closure decides if the yearOfVisit is already a key in the dictionary.

If not, a new key-value pair is created with the new year as the key and the first visitor of that year as the first element in the Visitor array. If the year is already a key in the dictionary, we get the corresponding Visitor array and add the next Visitor object to it. We end up with a dictionary that will hold 5 keys (the years 2010 to 2014) and the corresponding Visitor objects as values. We can now easily get the information we want:

This is only for demonstration purposes by the way. If you only would want the visitors for a certain year, there’s no need to write a complicated reduce function. We can use the ‘filter’ function instead, like this:

This post is about the reduce function only, so I won’t dive into other collection functions like filter, map and flatmap. Maybe another time.