Search code examples
pythoncombinationspython-itertoolscombinatoricsiterable

Is there an iterator in Python that gives the product but omits permutations of the classes itself?


Assume that I want to assign a color to 5 different balls and have 3 colors r,b and g. I would like to iterate over all these combinations. Preferably I would want to omit combinations that are equal up to permutation of the color classes. That means for example that I want to consider (r,b,b,b,b) and (g,r,r,r,r) as equal. I could use

itertools.product('rbg', repeat=5)

but this would overcount by a lot. Maybe

itertools.combinations_with_replacement('rbg', 5)

would be better? I am not sure if this approach would not miss some. But it would certainly see (r,b,b,b,b) and (g,r,r,r,r) as different combinations. Is there anything better I could do?


Solution

  • Your sizes are small enough to filter the product, and I think this does what you mean:

    from itertools import product
    
    for p in product('rbg', repeat=5):
        f = ''.join(p).find
        if f('r') <= f('b') <= f('g'):
            print(p)
    

    The idea is to normalize by order of first appearance. To ignore the six permutations of the three colors, I picked one: check that the first appearing color is r (or it doesn't appear), the second is b, and the third is g.

    Output (Attempt This Online!):

    ('r', 'r', 'r', 'b', 'g')
    ('r', 'r', 'b', 'r', 'g')
    ('r', 'r', 'b', 'b', 'g')
    ('r', 'r', 'b', 'g', 'r')
    ('r', 'r', 'b', 'g', 'b')
    ('r', 'r', 'b', 'g', 'g')
    ('r', 'b', 'r', 'r', 'g')
    ('r', 'b', 'r', 'b', 'g')
    ('r', 'b', 'r', 'g', 'r')
    ('r', 'b', 'r', 'g', 'b')
    ('r', 'b', 'r', 'g', 'g')
    ('r', 'b', 'b', 'r', 'g')
    ('r', 'b', 'b', 'b', 'g')
    ('r', 'b', 'b', 'g', 'r')
    ('r', 'b', 'b', 'g', 'b')
    ('r', 'b', 'b', 'g', 'g')
    ('r', 'b', 'g', 'r', 'r')
    ('r', 'b', 'g', 'r', 'b')
    ('r', 'b', 'g', 'r', 'g')
    ('r', 'b', 'g', 'b', 'r')
    ('r', 'b', 'g', 'b', 'b')
    ('r', 'b', 'g', 'b', 'g')
    ('r', 'b', 'g', 'g', 'r')
    ('r', 'b', 'g', 'g', 'b')
    ('r', 'b', 'g', 'g', 'g')
    ('b', 'b', 'b', 'b', 'g')
    ('b', 'b', 'b', 'g', 'b')
    ('b', 'b', 'b', 'g', 'g')
    ('b', 'b', 'g', 'b', 'b')
    ('b', 'b', 'g', 'b', 'g')
    ('b', 'b', 'g', 'g', 'b')
    ('b', 'b', 'g', 'g', 'g')
    ('b', 'g', 'b', 'b', 'b')
    ('b', 'g', 'b', 'b', 'g')
    ('b', 'g', 'b', 'g', 'b')
    ('b', 'g', 'b', 'g', 'g')
    ('b', 'g', 'g', 'b', 'b')
    ('b', 'g', 'g', 'b', 'g')
    ('b', 'g', 'g', 'g', 'b')
    ('b', 'g', 'g', 'g', 'g')
    ('g', 'g', 'g', 'g', 'g')