What is the reduce() function doing, in Swift

Recall that reduce works by repeated applying a function (that is the closure you pass in) to an accumulator (that is the initial), for each element of the sequence:

var acc = initial
for element in array {
    acc = f(acc, element) // f is the closure
}

Now knowing that, this reduction will make a lot more sense if you give meaningful names to $0.0, $0.1 and $1. Here I have renamed $0 to (prev, total), and $1 to curr.

func countUniques<T: Comparable>(_ array: Array<T>) -> Int {
    let sorted = array.sorted()
    let initial: (T?,Int) = (.none, 0)
    
    let (_, total) = sorted.reduce(initial) { acc, curr in
        let (prev, total) = acc
        return (curr, prev == curr ? total : total + 1)
    }
    return total
}

prev is used to keep track of the previous element that we have seen. Notice how we always return curr as the first element of the pair. This is to say that the current element that we are seeing, becomes the “previous element” in the next iteration. Also note that it starts off .none (nil), as we have not seen anything yet.

If prev is not curr, we add 1 to total, otherwise we use the same total. In this way, we can count how many times we see a different element from the one just saw.

For a sorted array, “how many times we see a different element from the one just saw” is the same number as the number of unique elements, because the duplicates will all be grouped next to each other.

Leave a Comment