Reduce

The reduce function reduces a list into a single value. Often referred to as fold or aggregate, it takes two parameters: a starting value and a function.

A function takes a running total and an element of the list as parameters and returns a value that is created by combining the elements in the list.

Unlike map, filter, and flatMap, which would return the same type, reduce changes the type. In other words, map, filter, and flatMap would take Array and provide a changed Array. This is not the case with reduce as it can change an array to, for instance, a tuple or single value.

Swift provides the reduce method on arrays and has the following definition:

func reduce<T>(initial: T, @noescape combine: (T, 
  Self.Generator.Element) -> T) -> T

If we use the reduce method on our numbers Array, the result of this call becomes 394:

let total = numbers.reduce(0) { $0 + $1 }

We could also call reduce, as follows, as the + operator is a function in Swift:

let total = numbers.reduce(0, combine: +)

Like the map and filter methods, developing a reduce function is also simple:

func reduce<Element, Value>(elements: [Element],
                            initial: Value,
                            combine: (Value, Element) -> Value) ->     Value {
    var result = initial
 
    for element in elements {
        result = combine(result, element)
    }
 
    return result
}

We can achieve the same result (394) with the following call:

let total = reduce(elements: numbers, initial: 0) { $0 + $1 }

The reduce method can be used with other types such as arrays of Strings.

The map function in terms of reduce

The reduction pattern is so powerful that every other function that traverses a list can be specified in terms of it. Let's develop a map function in terms of reduce:

func mapIntermsOfReduce<Element, ElementResult>(elements: [Element],
  transform: Element -> ElementResult) -> [ElementResult] {
    return reduce(elements: elements, initial: [ElementResult]()) {
        $0 + [transform( $1 )]
    }
}

let result = mapIntermsOfReduce(elements: numbers, transform: { $0 + 2 })

The result is identical to our map function's result that we developed earlier in this chapter. This is a good example to understand the basics of reduce.

In the function body, we provide elements and an initial empty array of ElementResult, and finally, we provide a closure to combine the elements.

The filter function in terms of reduce

It is also possible to develop a filter function in terms of reduce:

func filterIntermsOfReduce<Element>(elements: [Element],
                                    predicate: Element -> Bool) -> [Element] {
    return reduce(elements: elements, initial: []) {
        predicate($1) ? $0 + [ $1 ] : $0
    }
}

let result = filterIntermsOfReduce(elements: numbers) { $0 % 2 == 0 }

Again, the result is identical to our previously developed filter function.

In the function body, we provide elements, an empty initial array, and finally predicate as a combinator.

The flatMap function in terms of reduce

To understand the power of reduce, we can implement the flatMap function in terms of reduce as well:

func flatMapIntermsOfReduce<Element>(elements: [Element],
  transform: (Element) -> Element?) -> [Element] {
    return reduce(elements: elements, initial: []) {
        guard let transformationResult = transform($1) else {
            return $0
        }
        return $0 + [transformationResult]
    }
}

let anArrayOfNumbers = [1, 3, 5]
let oneDimensionalArray = flatMapIntermsOfReduce(elements:
  anArrayOfNumbers) { $0 + 5 }

The flatten function in terms of reduce

Finally, let's implement the flatten function in terms of reduce:

func flattenIntermsOfReduce<Element>(elements: [[Element]]) -> [Element] {
    return elements.reduce([]) { $0 + $1 }
}

This function takes a two-dimensional array and converts it to a one-dimensional array. Let's test this function:

let flattened = flattenIntermsOfReduce(elements: [[1, 3, 5], [2, 4, 6]])

The result will be [1, 3, 5, 2, 4, 6].

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset