Python generator function and permutations

Viewed 130

Problem input: two lists [1,2,3] and [4,5,6]

Output: lists that begin with a permutation of [1,2,3] followed by a permutation of [4,5,6]

Example outputs are [1,2,3,4,5,6], [3,2,1,4,5,6], [3,2,1,6,5,4] etc. I want to loop through them using a generator.

I tried with the following script (Python3):

from itertools import permutations

def foo():
    perm_1 = permutations([1,2,3])
    perm_2 = permutations([4,5,6])

    for p1 in perm_1:
        for p2 in perm_2: 
            yield list(p1) + list(p2)

f = foo()

for ls in f:
    print(ls)

As outputs I get

[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 6, 5]
[1, 2, 3, 5, 4, 6]
[1, 2, 3, 5, 6, 4]
[1, 2, 3, 6, 4, 5]
[1, 2, 3, 6, 5, 4]

As you can see, the permutations of the first list are never used and e.g output [3,2,1,4,5,6] is never produced.

3 Answers

The problem here is that, once iterated, perm2 will be empty.

So, on the first iteration of the outer for loop, everything is fine. On the following iterations, however, perm2 will just be empty.

See a simpler example here:

>>> from itertools import permutations
>>> a = permutations([1,2,3])
>>> list(a)
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]
>>> list(a)
[]

To solve it, replace perm_2 with permutations([4,5,6])

(Another solution could be to convert perm_2 to a list when storing it but I think keeping everything with generators is more idiomatic)

The problem is here:

perm_1 = permutations([1,2,3])
perm_2 = permutations([4,5,6])

Once you load permutations this will never come again on you for loop.

try this instead and get each of them as a list:

perm_1 = list(permutations([1,2,3])) 
perm_2 = list(permutations([4,5,6])) 

I think it's happening because itertool's permutation method is implemented as a generator function under the hood. Since you are using a nested for loop, with p1 = (1, 2, 3), perm_2 generates all the possible permutations of the numbers in the list [4, 5, 6] and becomes exhausted. It is not possible to iterate over generator functions/expressions more than once so thats why the loop just ends with only possible ordering from perm_1.

Related