Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested for-loop: why is the inner loop only executed once?

I'm confused about the use of a double for loop in python, this is my code:

import numpy as np

range1 = np.linspace(1,6,10)
range2 = reversed(np.linspace(1,6,10))

for t1 in range1:
    print t1
    for t2 in range2:
        print t1,t2

The output is this:

1.0
1.0 6.0
1.0 5.44444444444
1.0 4.88888888889
1.0 4.33333333333
1.0 3.77777777778
1.0 3.22222222222
1.0 2.66666666667
1.0 2.11111111111
1.0 1.55555555556
1.0 1.0
1.55555555556
2.11111111111
2.66666666667
3.22222222222
3.77777777778
4.33333333333
4.88888888889
5.44444444444
6.0

It only executes the inner loop for the first value of the outer loop, why is this happening? How can I get it to loop over all combinations of the first and second variable?

like image 899
Steven Avatar asked Dec 04 '22 22:12

Steven


2 Answers

reversed() produces an iterator; once you reach the end of an iterator, you can't re-use it:

>>> it = reversed([1, 2, 3])
>>> list(it)
[3, 2, 1]
>>> list(it)
[]

Create a new iterator for the nested loop:

for t1 in range1:
    print t1
    for t2 in reversed(range1):
        print t1,t2

The reversed() documentation links to the iterator glossary entry:

When no more data are available a StopIteration exception is raised instead. At this point, the iterator object is exhausted and any further calls to its __next__() method just raise StopIteration again.

Bold emphasis mine.

like image 104
Martijn Pieters Avatar answered Dec 11 '22 17:12

Martijn Pieters


In every implementation that respects pythons data model the result of reversed can only be exhausted once (because it should return an iterator that is exhausted after the first traversal). After that iterator is exhausted it won't yield any items anymore. But you can simply reverse your array using slicing:

range2 = np.linspace(1,6,10)[::-1]

for t1 in range1:
    print t1
    for t2 in range2:
        print t1,t2

Basic slicing for numpy.arrays is very performant, it doesn't even need to copy the original.

Given that you use arrays you should be aware that iterating over them is a very slow operation because every value needs to be unboxed during the iteration. If you really need to iterate over one-dimensional arrays (hint: you generally don't) you should convert them to lists:

range1 = np.linspace(1,6,10).tolist()
range2 = np.linspace(1,6,10)[::-1].tolist()

Because tolist is more efficient at the unboxing compared to the (implicit) unboxing in a for-loop.

like image 24
MSeifert Avatar answered Dec 11 '22 16:12

MSeifert