makpalan
makpalan

Reputation: 145

Problem with nested for loop with zip() function, Python

I have a piece of code like this:

items1 = ['col1', 'col2']

items2 = ['a', 'b']
items3 = [1, 2]
data = zip(items2, items3)

for col in items1:
    print(col)
    for d in data:
        print(d)

and the output is:

col1
('a', 1)
('b', 2)
col2

It's like the for loop in 'data' works just once. My expected output was some:

col1
('a', 1)
('b', 2)
col2
('a', 1)
('b', 2)

It works if I invert the loops in the nested structure, like:

for d in data:
    print(d)
    for col in items1:
        print(col)

whose output is:

('a', 1)
col1
col2
('b', 2)
col1
col2

printing out all the information but not preserving the order, as I would like to.

Thanks in advance for any suggestion and I am sorry in case the format of the question was not compliant with the site rules (this is my first question here).

Upvotes: 3

Views: 1883

Answers (3)

Frank Yellin
Frank Yellin

Reputation: 11289

Worth noting that this was one of the big changes between Python 2 and Python 3. In Python 2, map, zip, range, filter, keys, values, items all returned lists. In Python 3, they return iterators.

If you are used to Python 2, this can be confusing at first.

Upvotes: 0

Kenny Ostrom
Kenny Ostrom

Reputation: 5871

zip produces an iterator. You use it up once and it's gone. Instead you can store it into a container such as a list, so you can iterate over it as many times as you want.

items1 = ['col1', 'col2']
items2 = ['a', 'b']
items3 = [1, 2]
data = list(zip(items2, items3))

for col in items1:
    print(col)
    for d in data:
        print(d)

Upvotes: 3

chepner
chepner

Reputation: 531325

Most (if not all) iterators can only be traversed once. The reason this seems confusing is that you are accustomed to iterating over lists, but lists are not iterators. They are iterable, because you can get an iterator for a list. A for loop implicitly calls iter on a list, but you can do so explicitly as well.

itr = iter([1,2,3])  # itr is a value of type list_iterator


# Fully consumes itr, outputting
#
#   1
#   2
#   3
for x in itr:
    print(x)

# Produces no output, because there is nothing left in itr to iterate over
for x in itr:
    print(x)

If you want to iterate over the result multiple times, you either need to call zip each time,

for col in items1:
    print(col)
    data = zip(items2, items3)

    for d in data:
        print(d)

or create a list from the zip object first.

data = list(zip(items2, items3))
for col in items1:
    print(col)
    for d in data:
        print(d)

Upvotes: 4

Related Questions