Lesson 48Closures

Filter & Reduce

Filter & Reduce

Two powerful higher-order functions that work perfectly with closures. filter selects elements, reduce combines them!

Filter vs Reduce

filter

Returns array of matching elements

.filter { $0 > 5 }

reduce

Returns single combined value

.reduce(0, +)

Filter Syntax

array.filter { element in
    // return true to keep
}

Reduce Syntax

array.reduce(initialValue) { accumulator, element in
    // return new accumulated value
}

Reduce Variants

reduceCreates new value each iteration
reduce(into:)Mutates result in place (faster)

Power of Chaining

Combine filter, map, and reduce for powerful data transformations!

numbers.filter { }.map { }.reduce(0, +)
main.swift
// FILTER - Keep elements that match a condition
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// Keep only even numbers
let evens = numbers.filter { $0 % 2 == 0 }
print(evens)  // [2, 4, 6, 8, 10]

// Keep numbers greater than 5
let big = numbers.filter { $0 > 5 }
print(big)  // [6, 7, 8, 9, 10]

// Multiple conditions
let special = numbers.filter { $0 > 3 && $0 < 8 }
print(special)  // [4, 5, 6, 7]

// FILTER WITH STRINGS
let words = ["apple", "banana", "cherry", "date", "elderberry"]

let longWords = words.filter { $0.count > 5 }
print(longWords)  // ["banana", "cherry", "elderberry"]

let startsWithB = words.filter { $0.hasPrefix("b") }
print(startsWithB)  // ["banana"]

// FILTER WITH OBJECTS
struct Product {
    let name: String
    let price: Double
    let inStock: Bool
}

let products = [
    Product(name: "iPhone", price: 999, inStock: true),
    Product(name: "MacBook", price: 1999, inStock: false),
    Product(name: "AirPods", price: 199, inStock: true)
]

let available = products.filter { $0.inStock }
let affordable = products.filter { $0.price < 500 }

// REDUCE - Combine all elements into one value
// reduce(initialValue) { accumulator, element in ... }

// Sum all numbers
let sum = numbers.reduce(0) { $0 + $1 }
print(sum)  // 55

// Or even shorter!
let sum2 = numbers.reduce(0, +)
print(sum2)  // 55

// Product of all numbers
let product = numbers.reduce(1, *)
print(product)  // 3628800

// Find maximum
let max = numbers.reduce(numbers[0]) { $0 > $1 ? $0 : $1 }
print(max)  // 10

// REDUCE WITH STRINGS
let letters = ["S", "w", "i", "f", "t"]
let word = letters.reduce("") { $0 + $1 }
print(word)  // "Swift"

// Join with separator
let joined = letters.reduce("") {
    $0.isEmpty ? $1 : $0 + "-" + $1
}
print(joined)  // "S-w-i-f-t"

// REDUCE INTO - More efficient for collections
// Avoids creating new instances each iteration
let sentence = "hello world hello swift world"
let wordFrequency = sentence.split(separator: " ").reduce(into: [:]) { counts, word in
    counts[String(word), default: 0] += 1
}
print(wordFrequency)  // ["hello": 2, "world": 2, "swift": 1]

// Group items
let grouped = numbers.reduce(into: [String: [Int]]()) { result, num in
    let key = num % 2 == 0 ? "even" : "odd"
    result[key, default: []].append(num)
}
print(grouped)  // ["even": [2,4,6,8,10], "odd": [1,3,5,7,9]]

// CHAINING FILTER + MAP + REDUCE
let scores = [85, 92, 78, 95, 88, 72, 90]

let result = scores
    .filter { $0 >= 80 }           // Keep passing scores
    .map { Double($0) }            // Convert to Double
    .reduce(0, +)                  // Sum them
let average = result / Double(scores.filter { $0 >= 80 }.count)
print("Average of passing: \(average)")

// PRACTICAL: Shopping cart total
struct CartItem {
    let name: String
    let price: Double
    let quantity: Int
}

let cart = [
    CartItem(name: "Apple", price: 1.50, quantity: 4),
    CartItem(name: "Bread", price: 2.50, quantity: 2),
    CartItem(name: "Milk", price: 3.00, quantity: 1)
]

let total = cart.reduce(0.0) { $0 + ($1.price * Double($1.quantity)) }
print("Cart total: $\(total)")  // $14.00

Try It Yourself!

Given [1,2,3,4,5,6,7,8,9,10], use filter and reduce to find the sum of all odd numbers!