skip to content

zip / combine / merge

zip pairs elements in lockstep, combine re-emits whenever any source produces a new value, and merge simply interleaves. The zip-versus-combine distinction is a favorite because picking wrong changes the output subtly rather than loudly.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What is the difference between zip and combine when joining two Flows in Kotlin?

level: juniorimportance: must knowfreq 70%

answer

  1. zip = lockstep pairs by index
  2. combine = latest-of-each, fires on any emission
  3. zip stops at the shorter flow, drops the rest
  4. combine needs every source to emit once first
  5. combine emits more often than zip

basics

~10 s

zip 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 s

Both 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 lines
kotlin
val 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

for a junior

States the core distinction: zip = lockstep pairs, combine = latest-of-each on any emission.

for a middle

Adds that zip stops at the shorter flow and drops extras, while combine needs a first value from each before emitting.

for a senior

Picks the right operator per use case (paired indices vs. latest-state) and notes combine's higher emission count and timing dependence.

for a principal

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

context

open as a page

Explain combine's seeding and conflation behavior: when does it first emit, and can intermediate values be skipped?

level: middleimportance: should knowfreq 45%

basics

~10 s

combine emits its first value only after every source has produced one. If a source emits faster than the collector consumes, combine may skip older values and use only the most recent of each.

open as a page

What does merge do with multiple Flows, and how does it differ from zip and combine?

level: middleimportance: should knowfreq 55%

basics

~10 s

merge runs several flows at once and forwards each item as it arrives into one flow. It does not pair or transform values — it just interleaves them in arrival order.

open as a page

You must build a derived UI state from three independent flows and also fan in raw events from many sources. Which combining operators do you choose and why, and what pitfalls do you guard against?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Use combine to build one UI state from the three inputs because it reacts to the latest of each. Use merge to pool the many same-type event flows into one stream. Avoid zip here — you don't want lockstep pairing.

open as a page

How does zip handle concurrency and backpressure between its two source flows, and what are the implications?

level: seniorimportance: should knowfreq 35%

basics

~10 s

zip collects both flows concurrently but emits a pair only when both have produced the next item. The faster flow waits for the slower one, so the slow side sets the pace.

open as a page