Lazy collections for performance in Swift - Time & Space Complexity
When using lazy collections, we want to see how the program's work changes as the input grows.
We ask: Does laziness make the program faster or slower as we handle more items?
Analyze the time complexity of the following code snippet.
let lazySquares = (1...n).lazy.map { $0 * $0 }
for square in lazySquares.prefix(5) {
print(square)
}
This code creates a lazy collection of squares from the numbers 1 to n, then prints only the first 5 squares.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Calculating squares for only the first 5 numbers.
- How many times: Exactly 5 times, no matter how big n is.
Even if the input grows, the program only calculates 5 squares.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 5 calculations |
| 100 | 5 calculations |
| 1000 | 5 calculations |
Pattern observation: The work stays the same even as input grows because of laziness.
Time Complexity: O(1)
This means the program does a fixed amount of work regardless of input size.
[X] Wrong: "Lazy collections always process the entire list."
[OK] Correct: Lazy collections only do work when needed, so if you take a small part, only that part is processed.
Understanding lazy collections helps you write efficient code that saves time by doing less work when possible.
"What if we removed the prefix(5) and printed all squares? How would the time complexity change?"
Practice
.lazy on a Swift collection?Solution
Step 1: Understand what lazy means in Swift collections
Lazy collections do not perform operations immediately but wait until the result is requested.Step 2: Compare options with lazy behavior
Only It delays computation until the results are actually needed. describes delaying computation, which matches lazy collections.Final Answer:
It delays computation until the results are actually needed. -> Option AQuick Check:
Lazy means delay work = A [OK]
- Thinking lazy processes all elements immediately
- Confusing lazy with sorting or converting to array
- Assuming lazy improves speed by precomputing
numbers in Swift?Solution
Step 1: Recall the syntax for lazy collections in Swift
In Swift,.lazyis a property, not a method, so no parentheses are used.Step 2: Check each option
let lazyNumbers = numbers.lazyis correct. Adding parentheses after.lazytreats it as a method (wrong).lazy(numbers)assumes a global function (doesn't exist).numbers.toLazy()uses a nonexistent method.Final Answer:
let lazyNumbers = numbers.lazy -> Option AQuick Check:
Lazy is a property, no parentheses = B [OK]
- Adding parentheses after .lazy
- Using a function call like lazy(numbers)
- Assuming .toLazy() exists
let numbers = [1, 2, 3, 4, 5]
let lazySquares = numbers.lazy.map { x in
print("Calculating \(x) * \(x)")
return x * x
}
print("Before accessing elements")
let first = lazySquares.first
print("First square: \(first!)")Solution
Step 1: Understand lazy map behavior
The map inside lazy does not run until elements are accessed. So print inside map runs only when first element is requested.Step 2: Trace the code execution order
"Before accessing elements" prints first. Then accessingfirsttriggers calculation and prints "Calculating 1 * 1". Finally, it prints the first square value.Final Answer:
Before accessing elements Calculating 1 * 1 First square: 1 -> Option CQuick Check:
Lazy delays map until first accessed = C [OK]
- Assuming map runs immediately on lazy collections
- Expecting all calculations before print statement
- Ignoring lazy evaluation order
let numbers = [1, 2, 3, 4, 5]
let lazyFiltered = numbers.lazy.filter { $0 % 2 == 0 }
let result = lazyFiltered.map { $0 * 2 }
print(result)Solution
Step 1: Understand lazy collection chaining
Lazy collections delay computation and produce a lazy sequence, not an array.Step 2: Check printing lazy sequences
Printing a lazy sequence directly shows its type info, not elements. To see elements, convert to array withArray(result).Final Answer:
The lazy collection must be converted to an array before printing. -> Option BQuick Check:
Print lazy sequence needs Array() conversion = D [OK]
- Trying to print lazy sequences directly
- Thinking lazy filter syntax is wrong
- Believing chaining map after filter is invalid
Solution
Step 1: Understand lazy evaluation for minimal processing
Using.lazydelays work and processes only as many elements as needed to find the first matching.Step 2: Analyze each option for efficiency
let result = numbers.lazy.map { $0 * 2 }.first { $0 > 1000 } uses lazy map and first with condition, so it doubles numbers one by one until it finds one > 1000, stopping early. let result = numbers.map { $0 * 2 }.filter { $0 > 1000 }.first processes entire map and filter eagerly. let result = numbers.filter { $0 > 500 }.map { $0 * 2 }.first filters before doubling but not lazy, so processes all. let result = numbers.lazy.filter { $0 > 1000 }.map { $0 * 2 }.first filters lazily but filters before doubling, which may skip needed elements.Final Answer:
let result = numbers.lazy.map { $0 * 2 }.first { $0 > 1000 } -> Option DQuick Check:
Lazy map + first with condition = minimal processing = A [OK]
- Using eager map and filter causing full processing
- Filtering before map may skip needed elements
- Not using lazy causing unnecessary work
Ready to prove it?
Pass the test and this pattern moves unknown
