Create Your Own Reduce Function in Swift

There’s an Iterator…and…

Image for post
Image for post
Photo by Noah Buscher on Unsplash

Reduce makes an Array a single function that is it combines all of the given elements in an array and outputs a single value (more on that in a minute) — according to the function we give it.

How is that implemented? What do we do?

Difficulty: Beginner | Easy | Normal | Challenging

Prerequisites:

Terminology

Array: An ordered series of objects which are the same type

Dictionary: The association between keys and values (where all the keys are of the same type, and all values are of the same type)

Reduce: A higher-order function that returns the result of combining the elements of a sequence using a closure

The Motivation

Reduce is one of the coolest higher — order functions available to us in Swift.

What if we could look about how reduce works under the hood, and perhaps mangle the functionality to be…whatever we would want it to be.

The reduce function

The original

The classic, canonical use is to use reduce to perhaps sum an Array

var arr = [1,2,3,4]
arr.reduce(0, {$0 + $1}) //10

This is, of course, using lots of magic from Swift’s type inference. The longer version (for the same array arr) does have the same result

arr.reduce(0, { sum, newVal in
return sum + newVal
}) // 10

which makes it slightly easier to read for beginners, and slightly more tricky for the more experienced (you can’t win).

There are variations on uses for the reduce function. Although Reduce works on any array it doesn’t have to return an Integer (like the example above) but can return other types.

What about returning a String to concatenate an array?

var names = ["James", "Ahemed", "Kim"]
names.reduce("", {$0 + $1})

This version of reduce just concatenates the array of Strings.

The original: using reduce to count frequencies

It might not seem amazing to perform the above functions with reduce, but reduce is more flexible than that!

The documentation gives us something to go on here. reduce(_:_:) has a declaration :

func reduce<Result>(_ initialResult: Result, _nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result

Notice the generic Result here: This can be any time. This means…it can be…a value, an array, or in the case of this example: A dictionary.

We can take an array of fruits:

var fruits = ["banana", "cherry", "orange", "apple", "cherry", "orange", "apple", "banana", "cherry", "orange", "fig"]

with which we are going to return a dictionary

fruits.reduce([:] as! [String: Int], {
a, b in
var c: [String:Int] = a
c[b, default: 0] += 1
return c
})

Although there is some tricky type casting going on, we can see that we have reduced the array down to a dictionary. This results in the following dictionary

["cherry": 3, "fig": 1, "apple": 2, "banana": 2, "orange": 3]

Our own reduce function

We can set up a function to, well reduce. The idea of this is to reproduce the in-built function.

A simple reduce function

This function is called (as shown above) with the following reduce(elements: test, initialResult: “”, nextPartialResult: {$0 + $1})

A reduce function in an extension

The tests

Let’s do this properly. Before writing this function, what do we expect it to do and what results do we expect it to give?

That is, we need to write some Unit Tests.

We can initially check the existing reduce function against these tests if this didn’t work I’d be very surprised (don’t worry, it does).

These tests are not complete, they are a rather basic suite to check if the extension performs as the original reduce (for production code more tests would be required to ensure that the function really does work as intended).

so we wish to create a new reduce function (myReduce) that operates the same way, that is on an array.

This sounds like an extension to me.

The extension

To understand this you will need some experience of iterators in Swift, and remember this is going to be called myReduce to match with the tests above.

myReduce is a generic function. This takes an initialResult and a nextPartialResult function in order to create a result of the type (generic) Result.

The initial result (of type Result) is set to the initial result (which is fine, since the function nextPartialResult has not yet been applied to any element of the input Array).

Entering a while loop with iterator.next(), which uses a while let in Swift (so only runs if iterator.next() is not nil) and uses try to run the nextPartialResult on the result and the nextElement which is then assigned to be the result.

TO test this within the playground the ReduceTests.defaultTestSuite.run() runs the (3 tests) — which all pass!

Joy!

Conclusion

The reduce function is fun!

Being aware that the reduce function can return more than a single value puts you ahead of most developers, but if you can code your own and think about how it really works underneath the hood you are doing extremely well.

This guide has taken you through just that, giving you some idea of reduce and how you can implement your own even including some testing.

I hope this has been an enjoyable article, and I hope to see you on the otherside.

Extend your knowledge

The Twitter contact:

Any questions? You can get in touch with me HERE

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store