Break Out of reduce()

On how you can escape from reduce() method earlier if you want

reduce() is a very useful method in the Swift Standard Library. It works like a for in loop (it is the one in fact), but it’s designed specifically to calculate a single value out of the elements in the collection. There is only one subtle difference — we cannot do this:

In fact we cannot do this out of the box, but the goal of my post is to show you how you can extend the Sequence protocol to achieve such goal and be able to break out of reduce.

This post is inspired by a question asked on the Stack Overflow and what follows is the answer to it. For TL;DR jump to the last section of the post or check out my playground here.

We can do this:

But now the if statement becomes part of the nextPartialResult closure and clutters the logic here. That’s not good. Let’s imagine a better solution. How about this:

That’s better — let’s see how we can implement it. The original reduce method is implemented on the Sequence protocol, so let’s put an overload in the extension:

Looks good, let’s give it a try:

Reduce a sequence of numbers with + operator until the partial sum becomes greater then 5.

It reads nicely, but there is one more issue.

If you run it in a playground (you can find my playground here) you’ll see “(6 times)”, and yes — if you increase the size of your sequence to 500 elements it’ll say “(501 times)” times. That’s because our condition closure is getting called n times, (where n is the size of the collection, + 1 is a call to reduce). So why do we need to invoke it as many times?

Computers and smartphones are fast, but we don’t want them to be wasteful and behave like that dog. In our case 3 iterations is all we really need…

In our overload (as in the original declaration) of the reduce method we can see that nextPartialResult that we’re implementing in our overload can throw an exception, so why not leverage it - throw an exception when we pass our condition, handle it so it won’t escape the scope of our extension and return a result.

To achieve it we’ll need an Error conforming type that will pass a Result object to the catch closure:

To finish it let’s have a full-fledged implementation, that allows us to make a “break it or make it” decision not only based on the partial result, but on the current element of the collection as well (although if it’s gonna be sth like element == someThing you should rather use prefix(while:) before reduce).

Here it is:

There is another variation of it and you should use it if you expect to reduce collection while the given condition is true:

It gives a different result, so you can use it when you don’t want to include the element above condition (as it is a case in until variation):

So that’s it!

I hope you enjoyed my second post. Feel free to give it a try, you can find the sample playground here.

I’m Maciek Czarnik

iOS Developer, musician, maker. Passionate about building beautiful, robust, useful and user-friendly apps. Contact for project inquiries.