What is the difference between zip and combine when joining two Flows in Kotlin?
answer
- zip = lockstep pairs by index
- combine = latest-of-each, fires on any emission
- zip stops at the shorter flow, drops the rest
- combine needs every source to emit once first
- combine emits more often than zip
basics
~10 szip waits for one new item from each flow and pairs them in lockstep. combine fires whenever either flow emits, using the newest value from the other flow.
solid answer
~40 sBoth zip and combine merge two (or more) Flows into one. zip is strictly paired: it takes the 1st of A with the 1st of B, the 2nd with the 2nd, and so on, waiting for both sides before emitting. It stops when the shorter flow completes, so leftover items are dropped. combine is latest-wins: after both flows have produced at least one value, every emission from either flow triggers a new combined value using the most recent value of the other. combine emits more often and never discards a 'paired index' — it reacts to whichever source changed. Use zip for in-step pairs (request/response indices), combine for keeping a derived state in sync with the latest inputs (e.g. UI state from several streams).
code
kotlin · 8 linesval nums = flowOf(1, 2, 3)
val letters = flowOf("a", "b")
// zip: lockstep, shorter wins -> 1a, 2b
nums.zip(letters) { n, l -> "$n$l" }.collect(::println)
// combine: latest-of-each -> reacts to whichever changed
nums.combine(letters) { n, l -> "$n$l" }.collect(::println)go deeper
States the core distinction: zip = lockstep pairs, combine = latest-of-each on any emission.
Adds that zip stops at the shorter flow and drops extras, while combine needs a first value from each before emitting.
Picks the right operator per use case (paired indices vs. latest-state) and notes combine's higher emission count and timing dependence.
Frames the choice in terms of correctness of derived state and backpressure/cancellation semantics across cold flows.
## The problem You often have more than one `Flow` and need a single stream that joins their values. Kotlin's `kotlinx.coroutines.flow` package gives three core combiners: `zip`, `combine`, and `merge`. This question contrasts the two value-joining ones. ## `zip` — lockstep pairing by index `zip` pairs elements **positionally**: element 0 of A with element 0 of B, element 1 with element 1, etc. To emit pair *n* it must wait until **both** flows have produced their *n*-th element. The transform you pass produces the combined value. - It completes (and cancels the other) as soon as **either** flow completes — extra trailing elements of the longer flow are **dropped**. - Backpressure is symmetric: a fast flow waits for the slow one. ```kotlin val nums = flowOf(1, 2, 3) val letters = flowOf("a", "b") // shorter nums.zip(letters) { n, l -> "$n$l" } .collect(::println) // 1a, 2b (3 is dropped) ``` ## `combine` — re-emit on the latest of each `combine` waits until **every** source has emitted at least once, then emits an initial combined value. After that, **any** emission from **any** source produces a new combined value using the **most recent** value of each other source. ```kotlin val a = flowOf(1, 2, 3) val b = flowOf("x", "y") a.combine(b) { n, s -> "$n$s" } .collect(::println) // e.g. 1x, 2x, 2y, 3y (exact interleaving is timing-dependent) ``` Notice it does **not** drop items and emits roughly `(emissions of A) + (emissions of B) - 1` times. There is also a vararg form `combine(vararg flows) { array -> ... }` and a `combineTransform { ... }` variant that can emit zero or many values per trigger. ## When to use which - **`zip`**: you genuinely need paired-by-index data — e.g. matching the *i*-th request to the *i*-th response. - **`combine`**: you want a derived value that should reflect the **latest** of several independent inputs — e.g. forming UI state from a username flow and a settings flow. ## Key APIs/keywords `Flow.zip`, `Flow.combine`, top-level `combine(...)`, `combineTransform`, `flowOf`, `collect`. All are cold-flow operators that run inside a coroutine and respect cancellation.
- If flow A has 5 items and flow B has 2, how many items does zip emit?Exactly 2 — zip stops when the shorter flow (B) completes, so the last 3 items of A are dropped.
- Does combine emit anything before both flows have produced a value?No. combine waits for every source to emit at least once before producing its first combined value.
zip is a zipper joining teeth one-for-one; combine is a dashboard that refreshes whenever any single gauge moves.
saying these in an interview costs you the question
- Saying zip and combine behave identically
- Claiming zip emits for every item of the longer flow
- Thinking combine pairs by index like zip
- Believing combine emits before all sources have a first value
- Assuming these operators run on a background thread automatically