skip to content

What does zipWithNext do, and how would you use it to detect changes or compute deltas in a sequence?

level: middleimportance: should knowfreq 45%

answer

  1. Pairs each element with its successor
  2. n elements -> n-1 pairs (empty if <2)
  3. = windowed(2) as Pairs
  4. Transform overload great for deltas
  5. count { a != b } -> transitions

basics

~20 s

zipWithNext pairs each element with the one right after it: (a,b), (b,c), (c,d). For n elements you get n-1 pairs. It is handy for comparing neighbors, like spotting where values change or computing gaps between them.

solid answer

~40 s

zipWithNext() returns List<Pair<T, T>> of consecutive adjacent pairs: element i with element i+1, giving size - 1 pairs (empty for 0 or 1 elements). It is exactly windowed(2) reshaped into Pairs. A transform overload zipWithNext { a, b -> ... } maps each adjacent pair to a result without allocating Pair — ideal for deltas: nums.zipWithNext { a, b -> b - a }. To detect change boundaries: list.zipWithNext().count { (a, b) -> a != b } counts transitions, or zipWithNext { a, b -> a != b } yields a Boolean per gap. It is available on Iterable and lazily on Sequence. Compared to windowed(2), zipWithNext is more ergonomic because you get two named values instead of indexing a sublist.

code

kotlin · 4 lines
kotlin
val readings = listOf(10, 13, 13, 9)
println(readings.zipWithNext())                    // [(10,13),(13,13),(13,9)]
println(readings.zipWithNext { a, b -> b - a })    // [3, 0, -4]
println(readings.zipWithNext().count { (a,b) -> a != b }) // 2 transitions

go deeper

for a junior

Knows it pairs neighbors and gives n-1 pairs.

for a middle

Uses the transform overload for deltas and change detection; knows the empty edge case.

for a senior

Relates it to windowed(2) and zip(drop(1)), and picks the lazy Sequence variant for streams.

for a principal

Weighs zipWithNext readability vs windowed for k>2, and reasons about allocation/laziness for hot paths and large inputs.

## What zipWithNext does `zipWithNext()` zips a collection **with itself shifted by one**, producing pairs of **adjacent neighbors**: ```kotlin listOf(1, 2, 3, 4).zipWithNext() // [(1, 2), (2, 3), (3, 4)] ``` For `n` elements you get **`n - 1`** pairs. With 0 or 1 elements the result is **empty** (no neighbor to pair). It is conceptually `windowed(2)` but returns `Pair<T, T>` instead of `List<T>`, which reads more cleanly. ## Transform overload (no Pair allocated) ```kotlin val prices = listOf(100, 120, 115, 130) val deltas = prices.zipWithNext { prev, next -> next - prev } // [20, -5, 15] ``` The lambda receives the two adjacent elements directly as named parameters — cleaner than destructuring a `Pair` or indexing a window. ## Detecting changes / boundaries Because each pair is `(current, next)`, neighbor comparisons are natural: ```kotlin val states = listOf("on", "on", "off", "off", "on") // number of transitions (where the value changes) val transitions = states.zipWithNext().count { (a, b) -> a != b } // 2 // a Boolean flag per gap val changedAt = states.zipWithNext { a, b -> a != b } // [false, true, false, true] // is the list strictly increasing? val increasing = listOf(1, 2, 3).zipWithNext().all { (a, b) -> a < b } // true ``` ## Relationship to other operators - `zipWithNext()` == `windowed(2) { (a, b) -> a to b }` in effect. - It is the special **adjacent-pair** case of `zip`: `list.zip(list.drop(1))` gives the same pairs. - Works on `Iterable` (eager `List`) and on `Sequence` (lazy). ## Gotchas - Returns **empty**, not an error, for size < 2 — guard if you need at least one pair. - It only sees **pairs**; for triples or larger neighborhoods use `windowed(k)`.

  • How many pairs does zipWithNext produce for a single-element list?
    Zero — there is no following element, so the result is empty (and likewise empty for an empty list).
  • How would you check that a list is sorted ascending using zipWithNext?
    list.zipWithNext().all { (a, b) -> a <= b } — every adjacent pair must be non-decreasing.

Like reading a thermometer log and noting the change between each reading and the next — every gap, not every value.

saying these in an interview costs you the question

  • Saying it produces n pairs instead of n-1
  • Expecting it to throw on a 1-element list instead of returning empty
  • Confusing it with zip of two different collections
  • Thinking it gives overlapping triples rather than adjacent pairs
  • Not knowing the transform overload exists for deltas

context