Combining flows (zip, combine) in Kotlin - Time & Space Complexity
When we combine two flows in Kotlin, we want to know how the work grows as the flows get bigger.
We ask: how many steps does the program take when merging these flows?
Analyze the time complexity of the following code snippet.
val flow1 = flowOf(1, 2, 3)
val flow2 = flowOf("a", "b", "c")
val zippedFlow = flow1.zip(flow2) { num, str -> "$num$str" }
zippedFlow.collect { println(it) }
This code combines two flows by pairing their elements one by one and then prints each pair.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Pairing each element from the first flow with one from the second flow.
- How many times: Once for each element in the smaller flow until one flow ends.
As the flows get longer, the number of pairs grows with the size of the smaller flow.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 pairs created |
| 100 | 100 pairs created |
| 1000 | 1000 pairs created |
Pattern observation: The work grows directly with the number of elements to combine.
Time Complexity: O(n)
This means the time to combine grows in a straight line with the number of elements.
[X] Wrong: "Combining two flows takes time proportional to the product of their sizes."
[OK] Correct: The combination stops when the smaller flow ends, so it only grows with the smaller size, not both multiplied.
Understanding how combining streams or flows scales helps you write efficient reactive programs and explain your reasoning clearly.
"What if we used combine instead of zip, which emits on any new element from either flow? How would the time complexity change?"
Practice
zip function do when combining two Kotlin flows?Solution
Step 1: Understand
Thezipbehaviorzipfunction pairs values from two flows one by one, waiting for both to emit before producing a pair.Step 2: Compare with other options
combinemerges latest values on any emission, notzip. Other options describe different behaviors.Final Answer:
Pairs values one by one from both flows, emitting pairs only when both have emitted. -> Option AQuick Check:
zip pairs values one by one = A [OK]
- Confusing zip with combine behavior
- Thinking zip merges latest values on any emission
- Assuming zip concatenates values into a list
flowA and flowB using combine in Kotlin?Solution
Step 1: Recall
combineextension syntaxcombineis called as an extension on one flow with another flow as argument and a lambda combining values.Step 2: Check options
flowA.combine(flowB) { a, b -> a + b } matches the correct syntax. flowA.zip(flowB) { a, b -> a + b } useszip, C uses top-levelcombinewhich is invalid, D uses non-existentmergewith lambda.Final Answer:
flowA.combine(flowB) { a, b -> a + b } -> Option AQuick Check:
combine is an extension function = B [OK]
- Using zip instead of combine
- Trying to call combine as a top-level function
- Using merge with a lambda (not valid)
val flow1 = flowOf(1, 2, 3)
val flow2 = flowOf("A", "B", "C", "D")
runBlocking {
flow1.zip(flow2) { a, b -> "$a$b" }
.collect { println(it) }
}Solution
Step 1: Understand
zipbehavior with unequal flow lengthszippairs elements one by one until the shortest flow ends. Here, flow1 has 3 elements, flow2 has 4.Step 2: Determine output pairs
Pairs: (1, "A"), (2, "B"), (3, "C"). The extra "D" in flow2 is ignored.Final Answer:
1A 2B 3C -> Option BQuick Check:
zip stops at shortest flow length = C [OK]
- Expecting zip to emit all values from longer flow
- Confusing zip with combine behavior
- Mixing order of concatenation in output
combine and fix it:val flow1 = flowOf(1, 2)
val flow2 = flowOf("X", "Y")
runBlocking {
flow1.combine(flow2) { a, b -> "$a$b" }
.collect { println(it) }
}Solution
Step 1: Check for common mistakes with
combinecombineis an extension function requiring import fromkotlinx.coroutines.flow.Step 2: Identify missing import
Withoutimport kotlinx.coroutines.flow.combine, code won't compile. Other options are incorrect because combine works on flowOf and lambda parameter order is correct.Final Answer:
Missing import for combine; add import kotlinx.coroutines.flow.combine -> Option DQuick Check:
Missing import causes compile error = D [OK]
- Forgetting to import combine function
- Thinking combine is not available on flowOf
- Swapping lambda parameters incorrectly
flowA and flowB so that every time either emits, you get the latest values from both. Which function should you use and why?Solution
Step 1: Understand the requirement
You want to emit combined latest values whenever either flow emits, not just pair one by one.Step 2: Match function behavior
combinemerges latest values from both flows on any emission.zipwaits for pairs,mergejust merges emissions without combining, andflatMapConcatflattens sequences.Final Answer:
Use combine because it emits on any flow emission with latest values from both. -> Option CQuick Check:
combine merges latest values on any emission = A [OK]
- Choosing zip instead of combine for latest values
- Confusing merge with combine
- Using flatMapConcat which flattens sequences, not combines
Ready to prove it?
Pass the test and this pattern moves unknown
