zip

zip(): creates an iterator that will aggregate elements from two or more iterables.

According to the official documentation, Pythonโ€™s zip() function behaves as follows:

Returns an iterator of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables. The iterator stops when the shortest input iterable is exhausted. With a single iterable argument, it returns an iterator of 1-tuples. With no arguments, it returns an empty iterator.

Python zip operations work just like the physical zipper on a bag or pair of jeans. Interlocking pairs of teeth on both sides of the zipper are pulled together to close an opening.

Use zip() in python

zip(*iterables):

  • takes in iterables as arguments and returns an iterator

  • generates a series of tuples containing elements from each iterable

  • can accept any type of iterable, such as files, lists, tuples, dictionaries, sets, and so on.

Pass n arguments

# Pass n arguments
numbers = [1, 2, 3]
letters = ['a', 'b', 'c']
upper_letters = ['A', 'B', 'C']
zipped = zip(numbers, letters, upper_letters)
zipped
<zip at 0x62479ae08>
list(zipped)
[(1, 'a', 'A'), (2, 'b', 'B'), (3, 'c', 'C')]
num_tuple = (1, 2)
lettet_tuple = ('a', 'b')
upper_letter_tuple = ('A', 'B')
list(zip(num_tuple, lettet_tuple, upper_letter_tuple))
[(1, 'a', 'A'), (2, 'b', 'B')]

Pass no arguments

# Passing no argument
zipped = zip()
zipped
<zip at 0x62473c908>
list(zipped)
[]

Pass one arguments

# Pass one argument
zipped = zip(numbers)
list(zipped)
[(1,), (2,), (3,)]

Pass arguments of unequal length:

the number of elements that zip() puts out will be equal to the length of the shortest iterable. The remaining elements in any longer iterables will be totally ignored by zip()

list(zip(range(5), range(100)))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]

If trailing or unmatched values are important, then use itertools.zip_longest() instead of zip()

from itertools import zip_longest

longest = range(5)
zipped = zip_longest(numbers, letters, longest, fillvalue='?')
list(zipped)
[(1, 'a', 0), (2, 'b', 1), (3, 'c', 2), ('?', '?', 3), ('?', '?', 4)]

Loop Over Multiple Iterables

Looping over multiple iterables is one of the most common use cases for Pythonโ€™s zip() function

Traverse lists in parallel

letters
['a', 'b', 'c']
numbers
[1, 2, 3]
for l,n in zip(letters, numbers):
    print(f'letter: {l}')
    print(f'number: {n} \n')
letter: a
number: 1 

letter: b
number: 2 

letter: c
number: 3 

Traverse dictionaries in parallel

dict_one = {'name': 'John', 'last_name': 'Doe', 'job': 'Python Consultant'}
dict_two = {'name': 'Jane', 'last_name': 'Doe', 'job': 'Community Manager'}

for (k1, v1), (k2, v2) in zip(dict_one.items(), dict_two.items()):
    print(k1, '->', v1)
    print(k2, '->', v2, '\n')
name -> John
name -> Jane 

last_name -> Doe
last_name -> Doe 

job -> Python Consultant
job -> Community Manager 

Unzip a sequence

zip(*zipped)

numbers
[1, 2, 3]
letters
['a', 'b', 'c']
zipped = zip(numbers, letters)
zipped_list = list(zipped)
zipped_list
[(1, 'a'), (2, 'b'), (3, 'c')]

We have a list of tuples and want to separate the elements of each tuple into independent sequences. To do this, we can use zip() along with the unpacking operator *,

list(zip(*zipped_list))
[(1, 2, 3), ('a', 'b', 'c')]

nums = [1, 2, 3]
nums = [1, 2, 3]
letters = [‘A’, ‘B’, ‘C’]
letters = [‘A’, ‘B’, ‘C’]
zipped_list = list(zip(nums, letters))
zipped_list = list(zip(nums, letters))
2
2
3
3
1
1
A
A
B
B
C
C
*zipped_list
*zipped_list
2
2
3
3
1
1
‘A’
‘A’
‘B’
‘B’
‘C’
‘C’
2
2
3
3
1
1
‘A’
‘A’
‘B’
‘B’
‘C’
‘C’
(
(
(
(
(
(
)
)
)
)
)
)
,
,
,
,
,
,
[
[
]
]
zipped_list
zipped_list
zip(*zipped_list)
zip(*zipped_list)
2
2
3
3
1
1
‘A’
‘A’
‘B’
‘B’
‘C’
‘C’
(
(
(
(
(
(
,
,
,
,
,
,
)
)
)
)
)
)
2
2
3
3
1
1
‘A’
‘A’
‘B’
‘B’
‘C’
‘C’
(
(
(
(
(
(
,
,
,
,
,
,
)
)
)
)
)
)
zip/
combine
zip/…
zip/
combine
zip/…
2
2
3
3
1
1
‘A’
‘A’
‘B’
‘B’
‘C’
‘C’
zip
zip
unzip
unzip
Viewer does not support full SVG 1.1

Sorting in parallel

Combine two lists and sort them at the same time.

numbers = [2, 4, 3, 1]
letters = ['b', 'a', 'd', 'c']
data1 = list(zip(numbers, letters))
data1
[(2, 'b'), (4, 'a'), (3, 'd'), (1, 'c')]
data1.sort() # sort by numbers
data1
[(1, 'c'), (2, 'b'), (3, 'd'), (4, 'a')]
data2 = list(zip(letters, numbers))
data2
[('b', 2), ('a', 4), ('d', 3), ('c', 1)]
data2.sort() # sort by letters
data2
[('a', 4), ('b', 2), ('c', 1), ('d', 3)]

Use sorted() and zip() together to achieve a similar result

data = sorted(zip(letters, numbers))
data
[('a', 4), ('b', 2), ('c', 1), ('d', 3)]

Calculating in pairs

total_sales = [52000.00, 51000.00, 48000.00]
prod_cost = [46800.00, 45900.00, 43200.00]

for sales, costs in zip(total_sales, prod_cost):
    profit = sales - costs
    print(f'Profit: {profit}')
Profit: 5200.0
Profit: 5100.0
Profit: 4800.0

Building Dictionaries

fields = ['name', 'last_name', 'age', 'job']
values = ['John', 'Doe', '45', 'Python Developer']

a_dict = dict(zip(fields, values))
a_dict
{'name': 'John', 'last_name': 'Doe', 'age': '45', 'job': 'Python Developer'}

Update an existing dictionary by combining zip() with dict.update().

new_job = ['Python Consultant']
field = ['job']

a_dict.update(zip(field, new_job))
a_dict
{'name': 'John', 'last_name': 'Doe', 'age': '45', 'job': 'Python Consultant'}