Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looping zipped list in python

I was toying around with the zip() function in python and discovered a problem while using the for loop. Here is my code:

list1 = ['monday', 'tuesday', 'wednesday', 'thursday']
list2 = [1, 2, 3, 4]

zipped_list = zip(list1, list2)

print(*zipped_list)  # unpacked zipped list

for a, b in zipped_list:   # for this to work comment the print(*zipped_list) statement
    print(a, b)

The output for this code is:

('monday', 1) ('tuesday', 2) ('wednesday', 3) ('thursday', 4)

Process finished with exit code 0

Now if I remove the print(*zipped_list) statement then the for loop gets executed correctly:

monday 1

tuesday 2

wednesday 3

thursday 4

Process finished with exit code 0

Why is this happening ?

like image 495
Arun Nair Avatar asked Feb 08 '23 18:02

Arun Nair


2 Answers

As pointed out in the first comment, the zip object is consumed with the first print(*zipped_list). However, you can convert the zip object to a list first like so to be able to use the values of zip object again:

zipped_list = list(zip(list1, list2))

A zip object is an Iterator. This Q/A from the link should explain why this happens:

Q: When would I need an extra iterator?

A: Iterator will typically need to maintain some kind of position state information (like the index of the last element returned or the like). If the iterable maintained that state itself, it would become inherently non-reentrant (meaning you could use it only one loop at a time).

Also take a look at the docs for zip. Zip is equivalent to:

def zip(*iterables):
    # zip('ABCD', 'xy') --> Ax By
    sentinel = object()
    iterators = [iter(it) for it in iterables]
    while iterators:
        result = []
        for it in iterators:
            elem = next(it, sentinel)
            if elem is sentinel:
                return
            result.append(elem)
        yield tuple(result)

See the yield statement? This makes it a generator like object. Hence looping over it once exhausts it. Note that just printing the zip object also exhausts it.

Since zip objects are generator like, they produce the elements on demand rather than expand an entire list into memory. The advantage this buys is greater efficiency in their typical use-cases.

like image 153
Sнаđошƒаӽ Avatar answered Feb 12 '23 10:02

Sнаđошƒаӽ


Shadowfax answered about the zip generator stuff. If you were wondering why you have new lines...

print(*zipped_list) # => print(elm1, elm2 ,elm3...) now newlines (only one in the end)

But like this:

 for a, b in zipped_list:   
     print(a, b) # each print will do a newline in the end so you have many rows...
like image 29
Yoav Glazner Avatar answered Feb 12 '23 11:02

Yoav Glazner