Lesson 50Closures
Closures Practice
Module Complete!
Time to practice everything you've learned about closures. Complete these exercises to solidify your understanding!
Exercises Overview
1. Basic Closures
Create closure expressions
2. Trailing Closures
Use clean trailing syntax
3. Filter & Map
Chain transformations
4. Reduce
Combine values
5. Higher-Order
Create custom functions
6. Capturing
Value capture patterns
7. @escaping
Async closure handling
8. CompactMap
Handle optionals
9. Sorting
Custom sort logic
10. Lazy
Performance optimization
What You've Learned
- Closure syntax and shorthand forms
- Trailing closure syntax
- Capturing values (by reference & value)
- @escaping and @autoclosure
- map, filter, reduce, compactMap
- Best practices and memory management
Next Up: Structs!
In the next module, you'll learn about Structs - Swift's powerful value types for organizing data and behavior!
practice.swift
// CLOSURES PRACTICE - PUTTING IT ALL TOGETHER!
// ===== EXERCISE 1: Basic Closures =====
// Create a closure that takes two Ints and returns their average
let average: (Int, Int) -> Double = { a, b in
Double(a + b) / 2.0
}
print(average(10, 20)) // 15.0
// ===== EXERCISE 2: Trailing Closures =====
// Use map with trailing closure to square each number
let numbers = [1, 2, 3, 4, 5]
let squared = numbers.map { $0 * $0 }
print(squared) // [1, 4, 9, 16, 25]
// ===== EXERCISE 3: Filter & Map Chain =====
// Get names of adults (age >= 18) in uppercase
struct Person {
let name: String
let age: Int
}
let people = [
Person(name: "Alice", age: 25),
Person(name: "Bob", age: 15),
Person(name: "Charlie", age: 30),
Person(name: "Diana", age: 12)
]
let adultNames = people
.filter { $0.age >= 18 }
.map { $0.name.uppercased() }
print(adultNames) // ["ALICE", "CHARLIE"]
// ===== EXERCISE 4: Reduce =====
// Calculate total price of in-stock items
struct Item {
let name: String
let price: Double
let inStock: Bool
}
let inventory = [
Item(name: "Laptop", price: 999.99, inStock: true),
Item(name: "Mouse", price: 29.99, inStock: true),
Item(name: "Keyboard", price: 79.99, inStock: false),
Item(name: "Monitor", price: 299.99, inStock: true)
]
let inStockTotal = inventory
.filter { $0.inStock }
.reduce(0.0) { $0 + $1.price }
print("In-stock total: $\(inStockTotal)") // $1329.97
// ===== EXERCISE 5: Custom Higher-Order Function =====
// Create a function that applies a transformation n times
func applyNTimes<T>(_ value: T, times: Int, transform: (T) -> T) -> T {
var result = value
for _ in 0..<times {
result = transform(result)
}
return result
}
let doubled = applyNTimes(2, times: 4) { $0 * 2 }
print(doubled) // 32 (2 -> 4 -> 8 -> 16 -> 32)
// ===== EXERCISE 6: Capturing Values =====
// Create a counter factory
func makeCounter(startAt: Int = 0, step: Int = 1) -> () -> Int {
var count = startAt
return {
count += step
return count
}
}
let counter = makeCounter()
print(counter()) // 1
print(counter()) // 2
print(counter()) // 3
let tenCounter = makeCounter(startAt: 10, step: 5)
print(tenCounter()) // 15
print(tenCounter()) // 20
// ===== EXERCISE 7: Escaping Closure =====
// Simulate an async data loader
class DataLoader {
var completionHandlers: [(String) -> Void] = []
func loadData(completion: @escaping (String) -> Void) {
completionHandlers.append(completion)
}
func finishLoading(with data: String) {
for handler in completionHandlers {
handler(data)
}
completionHandlers.removeAll()
}
}
let loader = DataLoader()
loader.loadData { data in
print("Received: \(data)")
}
loader.finishLoading(with: "Hello, World!")
// ===== EXERCISE 8: CompactMap =====
// Parse valid integers from mixed array
let mixedStrings = ["1", "two", "3", "four", "5", "6"]
let validNumbers = mixedStrings.compactMap { Int($0) }
print(validNumbers) // [1, 3, 5, 6]
// ===== EXERCISE 9: Sorting with Closures =====
// Sort by multiple criteria
struct Student {
let name: String
let grade: Int
let age: Int
}
let students = [
Student(name: "Alice", grade: 90, age: 20),
Student(name: "Bob", grade: 85, age: 22),
Student(name: "Charlie", grade: 90, age: 19),
Student(name: "Diana", grade: 85, age: 21)
]
// Sort by grade (descending), then by age (ascending)
let sorted = students.sorted {
if $0.grade != $1.grade {
return $0.grade > $1.grade
}
return $0.age < $1.age
}
sorted.forEach { print("\($0.name): \($0.grade), \($0.age)") }
// ===== EXERCISE 10: Lazy Evaluation =====
// Demonstrate lazy vs eager evaluation
let largeArray = Array(1...1000000)
// Eager - processes all elements
let eagerResult = largeArray.filter { $0 % 2 == 0 }.map { $0 * 2 }.prefix(5)
// Lazy - processes only what's needed
let lazyResult = largeArray.lazy.filter { $0 % 2 == 0 }.map { $0 * 2 }.prefix(5)
print(Array(lazyResult)) // [4, 8, 12, 16, 20]
print("\nš Congratulations! You've completed the Closures module!")Challenge!
Create a function pipeline that takes an array of transformations [(Int) -> Int] and returns a closure that applies them all in sequence!