Reduce
Reduce is sort of a generalized version of map
, compactMap
, flatMap
, or
filter
. The basic idea is to reduce a sequence into a different
shape utilizing an accumulator that can keep incremental state. To
do this, we hand the function a combinator closure/function/method
which is called once for each item in the sequence. This may sound
complicated but becomes really easy with a couple of examples.
It is a method on SequenceType
and looks like this (simplified):
func reduce<T>(_ initialResult: T, _ nextPartialResult: (T, Self.Generator.Element) -> T) -> T
There're two parameters here:
- A
initialResult
value of generic typeT
- A closure
nextPartialResult
that receives two parameters and returns the generic typeT
. The two parameters areT
, once again, and the element type of the array. Imagine we had an array ofString
and we'd like toreduce
it to the count of elementsInt
. Reduce would look like this:
func reduce(_ initialResult: Int, _ nextPartialResult: (Int, String) -> Int) -> Int
So here we have an initial value Int
, and we have a closure which expects us to
return the same type as the initial value (Int
). The final value of the
operation is also of the same type as the initial value.
If we take a very simple reduce operation - counting the elments in an array of String
- , the evaluation will look like this:
func count(accumulator: Int, current: Int) -> Int {
return accumulator += 1
}
[1, 2, 3].reduce(0, count)
// The following steps will be performed
count(0, 1) { return 0 + 1 } = 1
count(1, 2) { return 1 + 1 } = 2
count(2, 3) { return 2 + 1 } = 3
= 6
And if we want to sum up the integer elements in an array of Int
, we'd write this:
func sum(accumulator: Int, current: Int) -> Int {
return accumulator + current
}
[1, 2, 3].reduce(0, sum)
// The following steps will be performed
sum(0, 1) { return 0 + 1 } = 1
sum(1, 2) { return 1 + 2 } = 3
sum(3, 3) { return 3 + 3 } = 6
= 6
The nextPartialResult closure (sum
in our example) will be called once for each item in the
list [1, 2, 3]
. The state will be kept in the accumulator variable
which is just an Integer.
Let's start re-implementing some of our other, trusted, functional
programming friends. In order to keep things simple for now, all these
functions will operate on Int
or Optional<Int>
; i.e. we will ignore
generics in here. Also, keep in mind that the implementations below
exist to explain the behaviour of reduce
. The native Swift
implementations are usually much faster compared to the reduce versions
below. Reduce shines in a different set of problems, which will be
explained further below.