If you need to create a single value from a sequence of elements, then the reduce(_:_:) method is the API you are looking for. In this episode of Swift Fundamentals, we take a look at Swift's reduce(_:_:) method. You learn about its syntax and when you shouldn't use it.

How to Use the reduce(::) Method?

Fire up Xcode and create a playground by choosing the Blank template from the iOS > Playground section if you want to follow along.

Reducing a Sequence of Elements in Swift

The reduce(_:_:) method is defined on sequences, such as sets, arrays, and dictionaries. Let's start with an array of numbers.

import Foundation

let numbers = [1, 3, 8, 2, 34]

We can use the reduce(_:_:) method to produce a single value from the array of numbers. Let's use the reduce(_:_:) method to calculate the sum of .

The reduce(_:_:) method accepts two arguments, an initial result and a closure. The closure is executed for every element of the sequence. The closure accepts two arguments, the partial result and an element of the sequence, and it returns a new partial result. The partial result the closure returns is passed in as the first argument of the closure the next time the closure is executed.

In this example, we set the initial result to 0. In the closure we pass to the reduce(_:_:) method, we add the element that is passed to the closure, an integer, to the partial result and return the result of the sum. The closure is executed five times because the sequence contains five elements. The partial result is 0 when the closure is executed for the first time and the closure returns 1. The partial result is 1 when the closure is executed for the second time and the closure returns 4, the sum of the partial result, 1, and the element, 3. The reduce(_:_:) method returns the result, which is the sum of the elements of the numbers array.

import Foundation

let numbers = [1, 3, 8, 2, 34]

let sum = numbers.reduce(0) { partialResult, number in
    partialResult + number
}

The reduce(_:_:) method has many more applications. The only requirement is that the type of the initial result is the same as the type of the value the closure returns. Let's calculate the maximum value of the elements of the numbers array.

import Foundation

let numbers = [1, 3, 8, 2, 34]

let max = numbers.reduce(0) { partialResult, number in
    if number > partialResult {
        return number
    } else {
        return partialResult
    }
}

Why Not a for Loop?

You could use a for loop to achieve the same result. Take a look at this example. Is this a better implementation? I think that is debatable. I prefer the implementation to be concise and focused. If we use a for loop, we need to declare a variable to hold the partial result while that is nicely encapsulated by the reduce(_:_:) method.

import Foundation

let numbers = [1, 3, 8, 2, 34]

var sum = 0
for number in numbers {
    sum += number
}

We can further clean up the implementation that uses the reduce(_:_:) method by using shorthand argument names. This looks quite nice. Right?

import Foundation

let numbers = [1, 3, 8, 2, 34]

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

We can do the same to calculate the maximum value of numbers array. While this is more concise, it isn't easy to understand due to the use of shorthand argument names and ternary operator.

import Foundation

let numbers = [1, 3, 8, 2, 34]

let max = numbers.reduce(0) { $0 < $1 ? $1 : $0 }

Reducing Dictionaries

The reduce(_:_:) method can also be used on dictionaries. In this example, we have a dictionary with keys of type String and values of type Int. The key is the name of a person and the value is the person's age. Let's find out what the age is of the oldest person of the group.

import Foundation

let people = [
    "Jane": 19,
    "John": 25,
    "Lucy": 25,
    "Mike": 21,
    "Matt": 39,
    "Sarah": 28
]

let person = people.reduce(0) { partialResult, element in
    if partialResult < element.value {
        return element.value
    } else {
        return partialResult
    }
}

Reducing Sets

The Set struct is a sequence and therefore also defines a reduce(_:_:) method. The idea is similar to what we previously covered.

import Foundation

let numbers: Set<Int> = [1, 2, 3, 4, 5]

let sum = numbers.reduce(0) { partialResult, number in
    partialResult + number
}

When Not to Use the reduce(::) Method

As with every tool, you need to know when not to use it. The reduce(_:_:) method can be used for a variety of tasks, but the common theme is producing a single value from a sequence of elements, such as sets, arrays, and dictionaries. Don't use it to map or filter the values of a sequence of elements. Take a look at this example.

import Foundation

let numbers = [1, 3, 8, 2, 34]

let evenNumbers = numbers.reduce(Array<Int>()) { partialResult, number in
    if number % 2 == 0 {
        return partialResult + [number]
    }

    return partialResult
}

We use the reduce(_:_:) method to filter out odd numbers from the numbers array. I hope you agree that the implementation feels a bit odd and the reduce(_:_:) method isn't the best tool for the task. Take a look at this example in which we use the filter(_:) method to achieve the same result.

import Foundation

let numbers = [1, 3, 8, 2, 34]

let evenNumbers = numbers.filter { $0 % 2 == 0 }

What's Next?

The reduce(_:_:) method is a useful tool to produce a single value from a sequence of elements. The syntax is easy to pick up and you can use it in a range of use cases.