Search code examples
pythoncombinationspython-itertools

Partial itertools.product in python


I would like to create the following list of tuples in Python, based on a list of possible values [0, 1, 2, 3]:

(0, 0,  0),  # all set to first value: 0
(0, 0,  1),
(0, 0,  2),
(0, 0,  3),
(0, 1,  0),
(0, 2,  0),
(0, 3,  0),
(1, 0,  0),
(2, 0,  0),
(3, 0,  0),
(3, 3,  3),   # all set to last value: 3

To summarize:

  • first value (0) for all elements of the tuples
  • each value of the list of values ([0, 1, 2, 3]) for a given element of the tuple and other elements set to 0
  • last value (3) for all elements of the tuples

What would be an efficient way to do it? ... maybe there is a magic function to do it?

I was first thinking of using itertools.product and then filtering:

list(product([0, 1, 2, 3], repeat=3))

... or maybe by using pandas (which looks a bit overkill though).


Solution

  • I found a super ugly way, that might need to be optimized (but at least it's working):

    [
     t for t in product(range(4), repeat=3)
     if all(e==0 for e in t) or all(e==3 for e in t) or sum([e!=0 for e in t])==1
    ]
    

    [EDIT]

    I found another way to build the list using chain and product:

    from itertools import chain, product
    
    values = list(range(4))  # basically: [0, 1, 2, 3]
    dflt = [values[0]] * 3  # basically: [0, 0, 0]
    list(
        chain(
            [tuple([values[0]] * 3)],
            (tuple(dflt[:i] + [v] + dflt[i + 1 :]) for i, v in product(range(3), values[1:])),
            [tuple([values[-1]] * 3)],
        )
    )
    

    That gives the following result:

    [(0, 0, 0),
     (1, 0, 0),
     (2, 0, 0),
     (3, 0, 0),
     (0, 1, 0),
     (0, 2, 0),
     (0, 3, 0),
     (0, 0, 1),
     (0, 0, 2),
     (0, 0, 3),
     (3, 3, 3)]