Skip to content
AgileLogics
6 min read

map, filter, and reduce

Prerequisites: Closures

These three methods, each taking a closure, replace most hand-written loops that build new collections.

map — transform every element

let prices = [10.0, 20.0, 30.0]
let withTax = prices.map { $0 * 1.2 }
print(withTax)

let names = ["ada", "linus"]
print(names.map { $0.uppercased() })
print(names.map(\.count))
[12.0, 24.0, 36.0]
["ADA", "LINUS"]
[3, 5]

\.count is a key path — a shorthand for { $0.count }.

filter — keep matching elements

let nums = Array(1...10)
print(nums.filter { $0 % 2 == 0 })
print(nums.filter { $0 > 7 }.count)
[2, 4, 6, 8, 10]
3

reduce — combine into one value

reduce starts with an initial value and combines each element into it:

let nums = [1, 2, 3, 4]
let total = nums.reduce(0) { sum, n in sum + n }
print(total)
print(nums.reduce(0, +))
print(nums.reduce(1, *))
10
10
24

compactMap — transform and drop the nils

let inputs = ["1", "two", "3", ""]
let numbers = inputs.compactMap { Int($0) }
print(numbers)
[1, 3]

compactMap is the everyday way to convert a list where some items might fail.

Chaining

let orders = [120.0, 45.0, 300.0, 80.0]
let bigOrdersTotal = orders
    .filter { $0 > 100 }
    .map { $0 * 0.9 }
    .reduce(0, +)
print(bigOrdersTotal)
378.0

Common mistakes

  • Using map when the closure returns an optional and you want to drop failures — that gives an array of optionals. Use compactMap.
  • Using forEach to build a new array. map and filter say what you mean directly.

Practice

Given let names = ["ada", "linus", "grace", "al"], produce an array of the names longer than 2 letters, capitalized.

Hint: "ada".capitalized needs import Foundation.

Show solution
import Foundation

let names = ["ada", "linus", "grace", "al"]
print(names.filter { $0.count > 2 }.map { $0.capitalized })
["Ada", "Linus", "Grace"]