Reputation: 7198
itertools documentation provides the following pseudo-code:
def product(*args, **kwds):
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
pools = map(tuple, args) * kwds.get('repeat', 1)
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
map(tuple, args)
looks redundant: could simply use args. Am I missing something?
Here is my test code (python 2.7):
def product2(*args, **kwds):
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
pools = args * kwds.get('repeat', 1)
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
print list (product(['A','B'],['C','D'])) == list (product2(['A','B'],['C','D']))
print list (product(['A','B'],['C','D'], repeat=2)) == list (product2(['A','B'],['C','D'], repeat=2))
print list (product([],[], repeat=2)) == list (product2([],[], repeat=2))
print list (product([])) == list (product2([]))
True
True
True
True
Upvotes: 0
Views: 570
Reputation: 1121962
Let's pass in iterators and see what happens:
>>> list(product(iter('AB'), iter('CD')))
[('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D')]
>>> list(product2(iter('AB'), iter('CD')))
[('A', 'C'), ('A', 'D')]
>>> list(product(iter('AB'), iter('CD'))) == list(product2(iter('AB'), iter('CD')))
False
Conclusion: you need to turn the arguments into tuples to capture all the values of the iterators.
It is even easier to illustrate when using only one iterator and the repeat option:
>>> list(product(iter('ABC'), repeat=2))
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('C', 'C')]
>>> list(product2(iter('ABC'), repeat=2))
[]
Upvotes: 4