3

Using pythons itertools, I'd like to create an iterator over the outer product of all permutations of a bunch of lists. An explicit example:

import itertools
A = [1,2,3]
B = [4,5]
C = [6,7]

for x in itertools.product(itertools.permutations(A),itertools.permutations(B),itertools.permutations(C)):
    print x

While this works, I'd like to generalize it to an arbitrary list of lists. I tried:

for x in itertools.product(map(itertools.permutations,[A,B,C])):
    print x

but it did not do what I intended. The expected output is:

((1, 2, 3), (4, 5), (6, 7))
((1, 2, 3), (4, 5), (7, 6))
((1, 2, 3), (5, 4), (6, 7))
((1, 2, 3), (5, 4), (7, 6))
((1, 3, 2), (4, 5), (6, 7))
((1, 3, 2), (4, 5), (7, 6))
((1, 3, 2), (5, 4), (6, 7))
((1, 3, 2), (5, 4), (7, 6))
((2, 1, 3), (4, 5), (6, 7))
((2, 1, 3), (4, 5), (7, 6))
((2, 1, 3), (5, 4), (6, 7))
((2, 1, 3), (5, 4), (7, 6))
((2, 3, 1), (4, 5), (6, 7))
((2, 3, 1), (4, 5), (7, 6))
((2, 3, 1), (5, 4), (6, 7))
((2, 3, 1), (5, 4), (7, 6))
((3, 1, 2), (4, 5), (6, 7))
((3, 1, 2), (4, 5), (7, 6))
((3, 1, 2), (5, 4), (6, 7))
((3, 1, 2), (5, 4), (7, 6))
((3, 2, 1), (4, 5), (6, 7))
((3, 2, 1), (4, 5), (7, 6))
((3, 2, 1), (5, 4), (6, 7))
((3, 2, 1), (5, 4), (7, 6))
Hooked
  • 84,485
  • 43
  • 192
  • 261

1 Answers1

12

You missed the * to unpack the list into 3 arguments

itertools.product(*map(itertools.permutations,[A,B,C]))
JBernardo
  • 32,262
  • 10
  • 90
  • 115
  • This solves the stated problem - but it has the unfortunate side effect of expanding the permutations into the full lists, completely undermining the intention of an iterator. When one of the lists is is even a medium size say 13, `N!` becomes a huge number when stored in memory. – Hooked Aug 22 '12 at 15:41
  • 1
    @Hooked No! It will expand the list with 3 iterators in 3 arguments (that are still iterators) – JBernardo Aug 22 '12 at 15:45
  • Let `A=range(13)` and the same for `B` and `C`. Granted there are 13!**3 elements in this iterator, but we should be able to walk through them (that's the whole point of iterators right?). The memory usage blows up before it lists a single one. Try it - do you not have the same effect? – Hooked Aug 22 '12 at 15:49
  • @Hooked it will happen in your original version as well. That's some `product` related problem... I'll try to check later (but both code run the same way) – JBernardo Aug 23 '12 at 02:48
  • 1
    @Hooked now I remember! That's quite simple: `product` needs to transform your iterators into lists before because they need to be looped many times (and an iterator can only be used once) – JBernardo Aug 23 '12 at 02:51
  • That's good to know - though it seems like there should be a way to repeat the iterators (say with itertools.cycle) so that product doesn't convert them. I'm going to try and ask it as a new question (http://stackoverflow.com/questions/12093364/cartesian-product-of-large-iterators-itertools) as you've solved this one already. Thanks again! – Hooked Aug 23 '12 at 13:59