Given a list l=[1,2]
I am trying to create a product of permutations. In other words, I am trying to create the following.
from itertools import permutations
l=[1,2]
print([(e1, e2) for e1 in permutations(l) for e2 in permutations(l)])
The above code prints [((1, 2), (1, 2)), ((1, 2), (2, 1)), ((2, 1), (1, 2)), ((2, 1), (2, 1))]
as expected.
However, if I use the code below,
from itertools import permutations
l=[1,2]
lp1 = permutations(l)
lp2 = permutations(l)
print([(e1, e2) for e1 in lp1 for e2 in lp2])
The code prints [((1, 2), (1, 2)), ((1, 2), (2, 1))]
.
I guess this is due to lp1
and lp2
pointing to the same iterator. But I do not understand why this is the case. Is this a intended behavior or is this a bug?
1
Yes. permutation
is a generator. You can use it only once.
Just to illustrate with an easier example, it is exactly as if you
tried
for i in range(3):
for j in enumerate([1,2,3]):
print(i,j)
To get
0 (0, 1)
0 (1, 2)
0 (2, 3)
1 (0, 1)
1 (1, 2)
1 (2, 3)
2 (0, 1)
2 (1, 2)
2 (2, 3)
And then were surprised that
range1=range(3)
range2=enumerate([1,2,3])
for i in range1:
for j in range2:
print(i,j)
was not working as expected, and gives:
0 (0, 1)
0 (1, 2)
0 (2, 3)
Because you need to recreate range2
for each i
iteration. Otherwise, j
with iterates only once. The 2 other times, the iterator is over.
(Edit note: initialy I used range(3)
in my example for range2
. But that is not a good example, since a range is a range, not a generator. So you can use it several times)
Another, simpler way to see it is
r=itertools.permutations([1,2])
list(r)
list(r)
First time, it gives the expected list. Containing everything generated by the generator `permutations([1,2]).
Second time, it gives an empty list. Because generator has nothing else to generate.
1
This should be, because permutations() gives you a generator of permutations. Once you stepped through it, it is exhausted and won’t generate any further elements.
The permutations of 0,1 are 0,1 and 1,0, which both generators will provide you.
Therefore, in the second version, you get exactly four elements.
In the first example, however, you create the permutation again and again for every iteration over the first permutation. Therefore, the code will step through the second permutations again, resulting in the longer list.
The difference between the two examples is:
[(e1, e2) for e1 in permutations(l) for e2 in permutations(l)] # ^^^^^^^^^^^^^^^
Here, a new permutations(l)
is created for each e1
.
lp2 = permutations(l) [(e1, e2) for e1 in lp1 for e2 in lp2])
Here, the same lp2
is reused for each e1
, but it is exhausted after the first time.
lp1 = permutations(l) lp2 = permutations(l)
[…]
I guess this is due to
lp1
andlp2
pointing to the same iterator.
No, lp1
and lp2
are distinct iterators.