Question

How do I create a Python generator like one produced by itertools.product(), but that iterates over a list of repeat values? It would behave like this nested for loop:

theSet = 'ABC'
thePowers = range(4)

for i in thePowers:
    for j in itertools.product(theSet, repeat=i):
        print j

But I'd like it to be a generator, such that this would produce the same output:

for p in myGenerator:
    print p
Was it helpful?

Solution

You could define a generator function for it..

>>> from itertools import product
>>> def my_gen(letters, powers):
...     for power in powers:
...         for cartesian in product(letters, repeat=power):
...             yield cartesian
...         
...     
... 
>>>

And use it like this:

>>> for p in my_gen("ABC", range(4)):
...    print p
()
('A',)
('B',)
('C',)
('A', 'A')
('A', 'B')
('A', 'C')
('B', 'A')
('B', 'B')
('B', 'C')
('C', 'A')
('C', 'B')
('C', 'C')
('A', 'A', 'A')
('A', 'A', 'B')
('A', 'A', 'C')
('A', 'B', 'A')
('A', 'B', 'B')
('A', 'B', 'C')
('A', 'C', 'A')
('A', 'C', 'B')
('A', 'C', 'C')
('B', 'A', 'A')
('B', 'A', 'B')
('B', 'A', 'C')
('B', 'B', 'A')
('B', 'B', 'B')
('B', 'B', 'C')
('B', 'C', 'A')
('B', 'C', 'B')
('B', 'C', 'C')
('C', 'A', 'A')
('C', 'A', 'B')
('C', 'A', 'C')
('C', 'B', 'A')
('C', 'B', 'B')
('C', 'B', 'C')
('C', 'C', 'A')
('C', 'C', 'B')
('C', 'C', 'C')

You can also use generator expressions!

>>> products = list(product("ABC", repeat=i) for i in range(4))
>>> result = list(x for lst in products for x in lst)
>>> result
[(), ('A',), ('B',), ('C',), ('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B
', 'B'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('C', 'C'), ('A', 'A', 'A'), ('A',
'A', 'B'), ('A', 'A', 'C'), ('A', 'B', 'A'), ('A', 'B', 'B'), ('A', 'B', 'C'), (
'A', 'C', 'A'), ('A', 'C', 'B'), ('A', 'C', 'C'), ('B', 'A', 'A'), ('B', 'A', 'B
'), ('B', 'A', 'C'), ('B', 'B', 'A'), ('B', 'B', 'B'), ('B', 'B', 'C'), ('B', 'C
', 'A'), ('B', 'C', 'B'), ('B', 'C', 'C'), ('C', 'A', 'A'), ('C', 'A', 'B'), ('C
', 'A', 'C'), ('C', 'B', 'A'), ('C', 'B', 'B'), ('C', 'B', 'C'), ('C', 'C', 'A')
, ('C', 'C', 'B'), ('C', 'C', 'C')]

OTHER TIPS

from itertools import product

def my_generator(values, *start_stop_step):
    for i in range(*start_stop_step):
        for j in product(values, repeat=i):
            yield ''.join(j)

for p in my_generator("ABC", 4):
    print(p)

which gives

   # <= that was a null string ie ''
A
B
C
AA
AB
AC
BA
BB
...
CCA
CCB
CCC

You can do this pretty easily using the 'yield' keyword. Here's a blog that I found very clear: https://www.jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/

import itertools

def iterate():
    theSet = 'ABC'
    thePowers = range(4)

    output = []
    for i in thePowers:
        for j in itertools.product(theSet, repeat=i):
            output.append(j)
    return output

def generate():
    theSet = 'ABC'
    thePowers = range(4)

    for i in thePowers:
        for j in itertools.product(theSet, repeat=i):
            yield j

a = iterate()
b = [output for output in generate()]
print(a == b) # True

The last statement assures us that the outputs are identical. I imagine you'll want to do something more complex than creating a list out of the generated values.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top