Python
inverse function
zip
programming
duplicate

What is the inverse function of zip in python?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Python does not provide a built-in function literally named unzip, but the inverse of zip is a standard idiom. If zip(a, b) turns columns into rows, then zip(*rows) turns those rows back into columns.

The Basic Inverse Pattern

Suppose you have paired data:

python
1pairs = [(1, "a"), (2, "b"), (3, "c")]
2
3numbers, letters = zip(*pairs)
4
5print(numbers)
6print(letters)

The star operator unpacks the list of tuples into separate arguments for zip. Conceptually, it is a transpose operation:

  • rows become columns
  • tuples in the outer sequence are unpacked
  • 'zip groups the first elements together, then the second elements, and so on'

The result is a tuple of tuples, not a list of lists. That detail matters if you need mutability later.

Convert the Result to Lists When Needed

If the caller expects lists, cast the outputs explicitly:

python
1pairs = [(1, "a"), (2, "b"), (3, "c")]
2
3numbers, letters = zip(*pairs)
4
5numbers = list(numbers)
6letters = list(letters)
7
8print(numbers)
9print(letters)

This is common in data-cleaning code where the transposed values need to be modified or appended to later.

It Works for Wider Records Too

The pattern is not limited to pairs. It works for any fixed-width row structure:

python
1rows = [
2    ("u1", 0.91, "active"),
3    ("u2", 0.42, "inactive"),
4    ("u3", 0.77, "active"),
5]
6
7user_ids, scores, states = zip(*rows)
8
9print(user_ids)
10print(scores)
11print(states)

This is a clean way to convert row-oriented records into separate columns for plotting, statistics, or function arguments that want one iterable per field.

Empty Input Needs Special Handling

The unpacking form fails on empty input because there are no columns to assign:

python
1rows = []
2
3# ValueError if you try:
4# a, b = zip(*rows)

If empty input is possible, guard it explicitly:

python
1def unzip_pairs(rows):
2    if not rows:
3        return [], []
4    left, right = zip(*rows)
5    return list(left), list(right)
6
7print(unzip_pairs([]))
8print(unzip_pairs([(10, "x"), (20, "y")]))

This keeps the failure mode predictable in pipelines where filtering may remove all rows.

Uneven Rows Need a Different Tool

The inverse idiom assumes each row has the same length. If rows are uneven, plain zip(*rows) truncates to the shortest row:

python
1rows = [
2    (1, "a", True),
3    (2, "b"),
4]
5
6print(list(zip(*rows)))

If you need to preserve all values, use itertools.zip_longest:

python
1from itertools import zip_longest
2
3rows = [
4    (1, "a", True),
5    (2, "b"),
6]
7
8columns = list(zip_longest(*rows, fillvalue=None))
9print(columns)

That gives every column a value for every row, using the fill value where data is missing.

Remember That zip Produces an Iterator

In Python 3, zip returns an iterator. Once consumed, it is exhausted:

python
1rows = [(1, 2), (3, 4)]
2z = zip(*rows)
3
4print(list(z))
5print(list(z))

If you need to reuse the transposed data, materialize it once:

python
1rows = [(1, 2), (3, 4)]
2columns = tuple(zip(*rows))
3print(columns)
4print(columns)

That avoids the common “works once, empty the second time” debugging session.

Think of It as Transposition, Not Magic

It helps to remember the mental model:

python
1names = ["Ada", "Grace"]
2scores = [95, 99]
3
4rows = list(zip(names, scores))
5print(rows)
6
7columns = list(zip(*rows))
8print(columns)

The first operation builds rows from columns. The second reverses that transformation. It is not a special inverse function with hidden behavior. It is the same zip function used in the opposite direction with unpacking.

Common Pitfalls

  • Expecting a built-in function literally named unzip.
  • Forgetting that zip(*rows) returns tuples rather than lists.
  • Unpacking empty input without a guard.
  • Losing data from uneven rows because plain zip truncates to the shortest iterable.
  • Reusing a consumed zip iterator after it has already been converted once.

Summary

  • The practical inverse of zip in Python is zip(*rows).
  • It transposes row-oriented tuples back into column-oriented groups.
  • Convert the results to lists if the caller needs mutable containers.
  • Guard against empty input when unpacking into fixed output variables.
  • Use zip_longest when row lengths differ and all values must be preserved.

Course illustration
Course illustration

All Rights Reserved.