Passing Swift's Operator Functions to Higher-Order Functions
I've already talked about operator functions in my previous two posts:
- Implementing a Custom Forward Pipe Operator for Function Chains in Swift
- Playing with Closure Expressions and Operator Functions in Swift
In Swift, operator functions are used to provide an implementation for an operator. They're normal functions and can therefore be used as such, for example as a parameter to a higher-order function like reduce
. Let's see how we can put that to use.
#Summing Up an Array of Numbers Using reduce
Assume you're given the following array of numbers:
let numbers = [2, 3, 5, 7]
How would you calculate the sum of all values in the array? Coming from a procedural background, you might iterate over the array using a for
-loop and add each number to a local variable:
var sum = 0
for number in numbers {
sum += number
}
// sum is 17
However, you can also choose a more functional approach and utilize the reduce
function with an initial value of 0 to which every number is added, step by step. Its combining function should receive the accumulated sum (up to that point) and the current value, add them together and return them.
The combining function should therefore have an (Int, Int) -> Int
signature. As it just so happens, the existing +
operator function fulfills this criterion perfectly. We can plug it right into reduce
:
let sum = numbers.reduce(0, +)
// 17
#Passing Binary Operator Functions to reduce
Let's now look at some other binary operator functions that we can pass as a combining function to reduce
. How about *
for multiplication? This time, we'll pass 1 as the initial value:
let product = numbers.reduce(1, *)
You're not restricted to just arithmetic operations, though. The +
operator can, for example, also be used to concatenate arrays. The initial value is an empty array in this case:
let primeSets = [[2, 3, 5], [7, 11], [13], []]
let combinedSets = primeSets.reduce([], +)
// [2, 3, 5, 7, 11, 13]
#Passing Unary Operator Functions to map
While reduce
works nicely with binary operator functions, map
requires a transformation function accepting a single parameter. That's exactly what unary operator functions can be used for. Here's how to quickly negate every value in an array of numbers using -
, the unary minus operator:
let primes = [2, 3, 5, 7, 11, 13]
let negatedPrimes = primes.map(-)
// [-2, -3, -5, -7, -11, -13]
A similar effect can be achieved for arrays containing Boolean values. The logical NOT operator !
will return the inverse value for each item in the array:
let logicalValues = [true, false, true]
let invertedValues = logicalValues.map(!)
// [false, true, false]
If you have other use cases where you pass operator functions to higher-order functions, please share them in the comments below!