reduce() is a very useful method in 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 difference.
We cannot do this:
This post is actually inspired by a question on Stack Overflow and I’m gonna show you how I’ve implemented it as an extension method on
Sequence. 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 the better solution, how about this:
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 (you can find code in my playground here):
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 a prepared 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
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
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. If you want to break a
reduce - you can :P