Dealing with multiple iterables in Python using zip()

Python’s zip() function creates an iterator that will aggregate elements from two or more iterables. zip() maps the similar index of multiple containers so that they can be used just using as single entity.

zip() is available built-in namespace.
'zip' in dir(__builtins__)

zip() takes in iterables and returns an iterator of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables.

## First example of zip()
atomic_num = [1, 2, 3, 6, 7, 8]
chem_element = ['H', 'He', 'Li', 'C', 'N', 'O']

# both iterables passed to zip() are lists
zipped = zip(chem_element, atomic_num)

# zipped holds an iterator object
<class 'zip'>

# extracting elements 
for tup in zipped:
('H', 1)
('He', 2)
('Li', 3)
('C', 6)
('N', 7)
('O', 8)

Here, zip(chem_element, atomic_num) returns an iterator that produces tuples of the form of (x,y). x values are taken from chem_element, and y values from atomic_num.

If we working with sequences like lists, tuples or strings then iterables are guaranteed to be evaluated from left to right. However for other types of iterables we may see weird behavior

## String and list as iterables passed to zip()

s = 'rgb'
colors = ['Red', 'Green', 'Blue']

for t in zip(s, colors):
('r', 'Red')
('g', 'Green')
('b', 'Blue')
## using zip() with sets
s1 = {12, 13,11}
s2 = {'l', 'm', 'k'}

for t in zip(s1, s2):
(11, 'k')
(12, 'm')
(13, 'l')

As we notice for sets , data is not extracted from left to right

Dealing with Iterables of Unequal Length

## using zip() with two iterables of unequal length

A = [1, 2, 3, 4, 5]
B = [20, 25, 27]

for t in zip(A, B):
(1, 20)
(2, 25)
(3, 27)

When using zip(), it is important to pay attention to the length iterables. It’s possible that the iterables we pass in as arguments aren’t the same length. In these cases, 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()

Using itertools.zip_longest()

from itertools import zip_longest
numbers = [1,2,3]
letters = ['a', 'b', 'c', 'd']
floats = [10.1, 11.2, 12.3, 13.4, 14.5, 15.6]

print("Using zip()\n--------------")
for t in zip(numbers, letters, floats):

print("\nUsing zip_longest()\n-----------------")
for t in zip_longest(numbers, letters, floats):
Using zip()
(1, 'a', 10.1)
(2, 'b', 11.2)
(3, 'c', 12.3)

Using zip_longest()
(1, 'a', 10.1)
(2, 'b', 11.2)
(3, 'c', 12.3)
(None, 'd', 13.4)
(None, None, 14.5)
(None, None, 15.6)

As we see, using zip_longest() the iteration will continue until the longest iterable is exhausted:

Comparing zip() in Python 3 and 2

Python’s zip() function works differently in both versions of the language.
In Python 2, zip() returns a list of tuples.
In Python 3, however, zip() returns an iterator.

## Python 2.7

X = [1,2,3]
Y = ['a','b','c']

zipped = zip(X,Y);

for t in zip(X,Y):
<type 'list'>
[(1, 'a'), (2, 'b'), (3, 'c')]
(1, 'a')
(2, 'b')
(3, 'c')

## Python 3.6
X = [1,2,3]
Y = ['a','b','c']

zipped = zip(X,Y);

for t in zip(X,Y):

<class 'zip'>
<zip object at 0x000002A5A9D1DC08>
(1, 'a')
(2, 'b')
(3, 'c')

Looping Over Multiple Iterables

Looping over multiple iterables is one of the most common use cases for Python’s zip() function. If you need to iterate through multiple lists, tuples, or any other sequence, then it’s likely that you’ll fall back on zip()

import numpy as np
s = 'A'*5
n = np.arange(1,6)

for letter,digit in zip(s,n):
    print("{}{}".format(letter, digit))


Traversing Dictionaries in Parallel

In Python 3.6 and beyond, dictionaries are ordered collections, meaning they keep their elements in the same order in which they were introduced. If you take advantage of this feature, then you can use the Python zip() function to iterate through multiple dictionaries in a safe and coherent way

student = {'name': ['Arjun', 'Ram', 'John'] }

stud_id = {'stud_id': [1,2,3]}

for k1, k2 in zip(student, stud_id):
    for v1, v2 in zip(student[k1], stud_id[k2]):
        print(v1, v2)
Arjun 1
Ram 2
John 3

Combining two lists and sorting in parallel

atomic_num = [1, 2, 3, 6, 7, 8]
chem_element = ['H', 'He', 'Li', 'C', 'N', 'O']

# Sort data in alphabetic order of chemical element name
data1 = list(sorted(zip(chem_element, atomic_num), key = lambda t : t[0]))

# Sort data in descending order of atomin number
data2 = list(sorted(zip(chem_element, atomic_num), key = lambda t : t[1], reverse=True))

[('C', 6), ('H', 1), ('He', 2), ('Li', 3), ('N', 7), ('O', 8)]
[('O', 8), ('N', 7), ('C', 6), ('Li', 3), ('He', 2), ('H', 1)]

Processing lists in parallel and doing calculation

sales = [50000, 56000, 62000, 70000]
cost  = [15000, 15000, 16000, 16000]
month = ['Jan', 'Feb', 'Mar', 'Apr']

for m,s,c in zip(month, sales, cost):
    print(f"For month {m}, Sales : {s}, Cost : {c}, Profit : {s-c}")
For month Jan, Sales : 50000, Cost : 15000, Profit : 35000
For month Feb, Sales : 56000, Cost : 15000, Profit : 41000
For month Mar, Sales : 62000, Cost : 16000, Profit : 46000
For month Apr, Sales : 70000, Cost : 16000, Profit : 54000

Build dictionaries using zip()

keys = ['rainbow', 'traffic', 'apple', 'banana']
values =['vibgyor', ['red', 'green', 'yellow'], ['red', 'green'], 'yellow']

items_dict = dict(zip(keys, values))
{'rainbow': 'vibgyor', 'traffic': ['red', 'green', 'yellow'], 'apple': ['red', 'green'], 'banana': 'yellow'}

Shekhar Pandey

Add comment

Follow us

Don't be shy, get in touch. We love meeting interesting people and making new friends.