AppDividend
Latest Code Tutorials

Python zip: How to Create Iterator from Iterables in Python

0

Python zip() function is the container that holds real data inside. The zip() function returns an iterator of tuples based on the iterable objects. If the given iterators have different lengths, the iterator with the least elements determines the length of the new iterator.

Python zip()

The zip() is a built-in Python function that creates an iterator that will aggregate elements from two or more iterables. The zip() function takes the iterable elements like input and returns the iterator. The zip() is available in the built-in namespace.

The zip() method returns the zip object, the iterator of tuples where the first item in each passed iterator is paired together. Then the second item in each given iterator is paired together. Thus, the zip() function takes iterables (can be zero or more), makes an iterator that aggregates items based on the iterables passed, and returns the iterator of tuples.

If you use the dir() function to inspect __builtins__, then you’ll see zip() at the end of the list.

print(dir(__builtins__))

You will see the long list, but in that, you will find the zip last. 

If the zip python function gets no iterable items, it returns the empty iterator.

If you are using IPython, then type zip? And check what zip() is about.

If you are not using IPython, install it: “pip3 install ipython” as I use Python 3. For Python3 users, pip install ipython will be just fine.

The syntax of the zip() function in Python is the following.

zip(*iterables)

# or

zip(iterator1, iterqator2, iterator3 ...)

The zip() function takes:

iterables – can be built-in iterables (like a list, string, dict) or user-defined iterables (an object that has an __iter__ method).

The zip() function returns the iterator of tuples based on an iterable object.

  1. If no parameters are passed on the zip function then, zip() returns the empty iterator.
  2. If a single iterable is passed to the zip function, zip() returns the iterator of 1-tuples. Meaning, the number of items in each tuple is 1.
  3. If multiple iterables are passed, ith tuple contains ith Suppose, and two iterables are given, one iterable containing 3 and the other containing five elements. Then, a returned iterator has three tuples. It’s because the iterator stops when the shortest iterable is exhausted.

Checking zip object in Python

If you use the zip() with n arguments, then that function will return the iterator that generates tuples of length n. We can use the Python type() function to determine its type.

#app.py

numbers = [11, 21, 46]
letters = ['e', 'k', 'a']
zipped = zip(numbers, letters)
print(type(zipped))

Output

python3 app.py
<class 'zip'>

Here, you use the zip(numbers, letters) to create the iterator that produces tuples of the form (x, y).

In this case, the x values are taken from the numbers, and y values are taken from letters.

Notice how the Python zip() function returns the iterator. Thus, to retrieve a final list object, you need to use the list() to consume the iterator.

Passing No Arguments in Python zip()

You call zip() with no arguments, so your zipped variable holds an empty iterator. If you consume the iterator with a list(), then you’ll see an empty list as well.

See the following code.

# app.py

zipped = zip()
print(list(zipped))

Output

python3 app.py
[]

You could also try to force the empty iterator to yield an element directly. In this case, you’ll get a StopIteration exception.

# app.py

zipped = zip()
next(zipped)

Output

python3 app.py
Traceback (most recent call last):
  File "app.py", line 2, in 
    next(zipped)
StopIteration

When you call the next() on zipped, Python tries to retrieve the next item. However, since zipped holds the empty iterator, there’s nothing to pull out, so Python raises the StopIteration exception.

Passing one argument

Python zip() function can take just one argument and returns an iterator that yields a series of 1-item tuples.

a = [11, 21, 19]

zippedObj = zip(a)

data = list(zippedObj)
print(data)

Output

[(11,), (21,), (19,)]

You see that the length of the resulting tuples will always equal the number of iterables you pass as arguments. Let’s give the three iterables.

a = [11, 21, 19]
b = ['hello', 'world', 'song']
c = [True, False, True]

zippedObj = zip(a, b, c)

data = list(zippedObj)
print(data)

Output

[(11, 'hello', True), (21, 'world', False), (19, 'song', True)]

Here, you call a Python zip method with three iterables(list of strings, integers, and booleans), so the resulting tuples have three items.

Using zip() with Python String

If you’re working with sequences like the strings, your iterables are guaranteed to be evaluated from left to right. So let’s define two strings and pass those in the zip() function and see the output.

strA = 'Python'
strB = 'Go'
zippedStr = zip(strA, strB)
data = str(zippedStr)
print(data)
print(type(data))

Output

<zip object at 0x103e46940>
<class 'str'>

Using zip() with Python set

If you’re working with sequences like sets, then the result might be weird. For example, if there are three items in two sets. Now, you zip the list and then convert the zipped object back to the list, but this time, the values will lose their orders.

setA = {'x', 'y', 'z'}
setB = {11, 21, 19}
zippedObj = zip(setA, setB)
listF = list(zippedObj)
print(listF)

Output

[('y', 19), ('z', 11), ('x', 21)]

In this example, setA and setB are set objects, which don’t keep their items in any particular order. Unfortunately, this means that the tuples returned by the zip() will have items that are paired up randomly.

If you’re going to use a Python zip() function with the unordered iterables like sets, this is something to keep in mind. 

Using zip() with Python list

The zip() function takes the list like the following.

a: a1 a2 a3 a4 a5 a6 a7...
b: b1 b2 b3 b4 b5 b6 b7...
c: c1 c2 c3 c4 c5 c6 c7...

And “zip” them into one list whose entries are 3-tuples (ai, bi, ci). Imagine drawing a zipper horizontally from left to right.

Write the following code inside the app.py file.

# app.py

numList = [19, 21, 46]
strList = ['one', 'two', 'three']

outputA = zip(numList, strList)
print(list(outputA))

outputB = zip(strList, numList)
print(list(outputB))

The output is the following.

Python Zip Example

We can also convert the output to the tuple. See the following code.

# app.py

numList = [19, 21, 46]
strList = ['one', 'two', 'three']

outputA = zip(numList, strList)
print(tuple(outputA))

outputB = zip(strList, numList)
print(tuple(outputB))

The output is the following.

➜  pyt python3 app.py
((19, 'one'), (21, 'two'), (46, 'three'))
(('one', 19), ('two', 21), ('three', 46))
➜  pyt

Python zip two lists

In python 3.0, the zip method returns the zip object.

You can get a list out of it by calling list(zip(a, b)).

If you want to merge lists into a list of tuples or zip two lists, you can use the zip() method. The pythonic approach is the following.

# app.py
listA = [19, 21, 46]
listB = ['one', 'two', 'three']
merge_list = zip(listA, listB)
print(list(merge_list))

See the output.

➜  pyt python3 app.py
[(19, 'one'), (21, 'two'), (46, 'three')]
➜  pyt

You have to know that a zip() function stops at the end of the shortest list, which may not always be what you want in the output.

The itertools module defines a zip_longest() method, which stops at the end of the longest list, filling missing values with something you provide as a parameter.

Unzipping the value using zip()

We can also extract the data from the Python zip function. If we want to remove the zip, we have to use the same zip()function. But we have to add an asterisk(*) in front of that list you get from the zipped variable.

We can also unzip the numList and strList. See the following example.

# app.py

numList = [19, 21, 46]
strList = ['one', 'two', 'three']

outputA = zip(numList, strList)

x, y = zip(*outputA )
print('numList = ', x)
print('strlist = ', y)

The output is the following.

➜  pyt python3 app.py
numList =  (19, 21, 46)
strlist =  ('one', 'two', 'three')
➜  pyt

The * operator can be used in conjunction with a zip to unzip the list.

You can use the list() function to get the list from the zipped variable. However, this will return several tuples. The number will differ according to the number of arguments that the zip function took to zip the data.

If the passed iterators have different lengths, the iterator with the least items decides the length of the new iterator. See the following example.

# app.py

numList = [19, 21, 46, 29]
strList = ['one', 'two', 'three']

outputA = zip(numList, strList)

print(list(outputA))

The numList has four items, and strList has three elements. So the lengths are not matched. Let’s see the output.

➜  pyt python3 app.py
[(19, 'one'), (21, 'two'), (46, 'three')]
➜  pyt

Zip three iterators

Let’s take an example in which we can use three iterators and then use the zip function on it.

# app.py

numList = [19, 21, 46]
strList = ['one', 'two', 'three']
setList = {'A1', 'B1', 'C1'}

outputA = zip(numList, strList, setList)

print(list(outputA))

The output is the following.

➜  pyt python3 app.py
[(19, 'one', 'C1'), (21, 'two', 'A1'), (46, 'three', 'B1')]
➜  pyt

We have taken three different variables and then use the zip() function, and then convert it into the iterable.

Comparing Python 2 zip() with Python 3 zip()

The zip() function works differently in both versions of the Python.

In Python 2, the zip() method returns a list of tuples. The output list is truncated to the length of the shortest input iterable. If you call the zip() with no arguments, then you get an empty list in return.

See the following code in Python2.

zipped = zip(range(3), 'WXYZ')

print(zipped)

Output

python2 app.py
[(0, 'W'), (1, 'X'), (2, 'Y')]

In this case, your call to the Python zip() method returns a list of tuples truncated at the value Z.

Now, let’s call a zip() with no arguments.

zipped = zip()

print(zipped)

Output

python2 app.py
[]

When you call the zip() method with no arguments, you get an empty list. 

If you supply no arguments to zip(), then the function returns an empty iterator.

zipped = zip()

print(zipped)

Output

python3 app.py
<zip object at 0x10c3a09c0>

When we give no argument to the zip() function in Python 3, you will get an empty iterator.

If you frequently use Python 2, then note that using the zip() method with long input iterables can inadvertently consume a lot of memory. In these cases, consider using the itertools.izip(*iterables) instead. This function creates the iterator that aggregates items from each of the iterables. It produces the same effect as the zip() function in Python 3. But I recommend that you please update the Python from 2 to 3 and use the Python 3 zip() function.

Looping Over Multiple Iterables

Python zip() function’s most use case is Looping over multiple iterables. If you need to iterate over multiple lists, tuples, or any other sequence, then it’s likely that you’ll recede on the zip(). 

Traversing Lists in Parallel

The zip() function allows us to iterate in parallel over two or more iterables. Since the zip() function generates tuples, you can unpack these in the header of a for loop.

dataStr = ['x', 'y', 'z']
dataInt = [11, 21, 19]

for a, b in zip(dataStr, dataInt):
    print(f'String: {a}')
    print(f'Integer: {b}')

Output

String: x
Integer: 11
String: y
Integer: 21
String: z
Integer: 19

To print the value in the console, we have formatted the string

Here, you iterate over the series of tuples returned by the zip() and unpacking the elements into a and b. When you combine the zip(), for loops, and tuple unpacking, you can get a convenient and Pythonic jargon for traversing two or more iterables at once.

You can also iterate over more than two iterables in a single for loop. Consider the below example, which has three input iterables.

dataStr = ['x', 'y', 'z']
dataInt = [11, 21, 19]
dataSpecial = ['&', '$', '@']

for a, b, c in zip(dataStr, dataInt, dataSpecial):
    print(f'String: {a}')
    print(f'Integer: {b}')
    print(f'Special: {c}')

Output

String: x
Integer: 11
Special: &
String: y
Integer: 21
Special: $
String: z
Integer: 19
Special: @

In this example, you have used the zip() with three iterables to create and return the iterator that generates 3-item tuples. This grants us to iterate over all three iterables in one go. There are no limitations on the number of iterables you can use with Python’s zip() function.

Traversing Dictionaries in Parallel using zip()

From Python 3.6 and beyond, dictionaries are ordered collections, meaning they keep their items in the same order they were lead first. If you take leverage of this aspect, then you can use the Python zip() function to iterate over multiple dictionaries safely and coherently.

dictA = {
    'name': 'Homer',
    'age': 50,
    'type': 'fat'
}

dictB = {
    'name': 'Bart',
    'age': 10,
    'type': 'medium'
}

for (key1, val1), (key2, val2) in zip(dictA.items(), dictB.items()):
    print(key1, '->', val1)
    print(key2, '->', val2)

Output

name -> Homer
name -> Bart
age -> 50
age -> 10
type -> fat
type -> medium

Here, you iterate through dictA and dictB in parallel. In this case, zip() creates tuples with the elements from both dictionaries. Then, you can unbox each tuple and gain access to the items of both dictionaries at the same time—kids’ stuff.

You can also use the zip() function to iterate over sets in parallel. However, you’ll have to consider that, unlike dictionaries in Python 3.6, sets don’t keep their items in order. If you forget this detail, the final output of your program may not be quite what you want or expect.

Sorting in Parallel

Let’s say you have to combine two lists(one is a list of ints and one is a list of strings) and sort them simultaneously. To do this, we can use zip() along with the sorted() method as follows.

dataStr = ['z', 'y', 'w', 'x']
dataInt = [19, 21, 18, 46]

zippyData = zip(dataInt, dataStr)
data = list(zippyData)
print(data)
print(sorted(data))

Output

[(19, 'z'), (21, 'y'), (18, 'w'), (46, 'x')]
[(18, 'w'), (19, 'z'), (21, 'y'), (46, 'x')]

In this case, sorted() runs over the iterator generated by the zip() and sorts the items by integers, all in one go. This way can be a little faster since you’ll need only two function calls: zip() and sorted().

With sorted(), you’re also writing the more general piece of code that totally makes sense to other programmers. For example, thiss will enable you to sort any sequence, not just lists.

Conclusion

In this in-depth tutorial, you’ve learned how to use Python’s zip() function. The zip() can receive multiple iterables as input and returns an iterator to create tuples with paired items from each argument. The final iterator can be quite useful when you need to process the multiple iterables in the single for loop and perform some actions on their items simultaneously. That is it for this tutorial.

Recommended Posts

Python ascii()

Python bin()

Python bool()

Python any()

Python all()

Leave A Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.