Terminal operations trigger execution in Kotlin - Time & Space Complexity
When working with database queries or streams, some operations only run when we ask for results.
We want to see how the time it takes grows when the final action triggers the work.
Analyze the time complexity of the following Kotlin code snippet.
val data = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val result = data.asSequence()
.filter { it % 2 == 0 }
.map { it * 2 }
.toList() // terminal operation triggers execution
This code creates a sequence from a list, applies filters and maps lazily, then collects results with a terminal operation.
Look at what repeats when the terminal operation runs.
- Primary operation: The filter runs once for each item and the map once for each even item when toList() is called.
- How many times: Each element in the original list is checked (filtered) exactly once; only even elements are transformed (mapped).
As the list gets bigger, the work grows in a simple way.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 filter + 5 map = 15 operations |
| 100 | 100 filter + 50 map = 150 operations |
| 1000 | 1000 filter + 500 map = 1500 operations |
Pattern observation: The total work grows directly with the number of items.
Time Complexity: O(n)
This means the time to get results grows in a straight line with the number of items.
[X] Wrong: "The filter and map run immediately when defined."
[OK] Correct: They actually wait until the terminal operation runs, so no work happens before then.
Understanding when work actually happens helps you write efficient queries and explain your code clearly.
"What if we replaced toList() with first()? How would the time complexity change?"
Practice
toList(), count(), and forEach() are examples of terminal operations. What is their main role?Solution
Step 1: Understand what terminal operations are
Terminal operations are the final step in a sequence or collection processing chain that triggers execution.Step 2: Identify the role of examples like
These operations produce a result or cause side effects, thus starting the actual processing.toList(),count(), andforEach()Final Answer:
They start the actual processing and produce results or side effects. -> Option AQuick Check:
Terminal operations trigger execution = B [OK]
- Thinking terminal operations only prepare data without running it
- Confusing terminal operations with intermediate operations
- Believing terminal operations do not produce results
numbers?Solution
Step 1: Identify terminal operations syntax
Terminal operations liketoList()are called with parentheses to execute and produce results.Step 2: Check each option
map()andfilter()are intermediate operations requiring arguments;sortedByis incomplete without parentheses.Final Answer:
numbers.toList() -> Option AQuick Check:
Correct terminal operation syntax = A [OK]
- Using intermediate operations as terminal without arguments
- Omitting parentheses on function calls
- Confusing intermediate and terminal operations
val numbers = sequenceOf(1, 2, 3, 4)
val result = numbers.filter { it % 2 == 0 }.count()What is the value of
result after execution?Solution
Step 1: Apply the filter condition
The filter keeps only even numbers: 2 and 4.Step 2: Count the filtered elements
There are 2 even numbers, socount()returns 2.Final Answer:
2 -> Option CQuick Check:
Count of even numbers = 2 [OK]
- Counting before filtering
- Assuming count returns the sequence itself
- Confusing sequence with list output
val numbers = listOf(1, 2, 3)
numbers.filter { it > 1 }Why does it not print or return any filtered list?
Solution
Step 1: Understand filter is intermediate
Thefilterfunction returns a new list but does not execute anything by itself.Step 2: Identify missing terminal operation
Without a terminal operation liketoList()orforEach(), the filtered list is not processed or printed.Final Answer:
Missing a terminal operation to trigger execution. -> Option BQuick Check:
Intermediate operations need terminal to run = D [OK]
- Thinking filter runs immediately
- Assuming immutability blocks filtering
- Believing filter syntax is wrong
val data = sequenceOf(0, 1, 2, 3, 4, 5)
val result = data
.filter { it > 0 }
.map { if (it % 2 == 0) it * 10 else it }
.toList()What is the content of
result after execution?Solution
Step 1: Filter out values greater than 0
Sequence after filter: 1, 2, 3, 4, 5 (0 is removed).Step 2: Map even numbers to value * 10, odd numbers unchanged
1 (odd) -> 1, 2 (even) -> 20, 3 (odd) -> 3, 4 (even) -> 40, 5 (odd) -> 5.Step 3: Convert sequence to list with
Final list: [1, 20, 3, 40, 5].toList()Final Answer:
[1, 20, 3, 40, 5] -> Option DQuick Check:
Filter then map then toList = C [OK]
- Forgetting filter removes 0
- Mapping all numbers instead of only even
- Missing toList() to trigger execution
Ready to prove it?
Pass the test and this pattern moves unknown
