Search code examples
pythonlistpython-itertoolscartesian-product

product of different length list using itertools in Python


I have the following lists:

sectors = ["A", "B"]

rows = [['1', '2', '3'], ['1', '2', '3', '4']]

seats = [['ab', 'abcd', 'ab'], ['ab', 'abcd', 'ab', 'abcd']]

and I want to create products like A1a, A1b, A2a, A2b, A2c ...

this code

  combinations = []
  for i in range(len(rows)):
    c = list(zip_longest(repeat(sectors[i], len(rows[i])), rows[i], seats[i]))
    combinations += c

  for c in combinations:
    for x in product(*c):
       print("".join(x))

prints the desired results as A1a A1b A2a A2b A2c A2d A3a ...

Can this be solved in a better and more readable way, I am practicing itertools and it is a bit confusing for me.


Solution

  • Not sure if that is what you want or if it is more elegant:

    from itertools import chain, product
    
    combinations = product(
        sectors,
        chain.from_iterable(chain.from_iterable(rows)),
        chain.from_iterable(chain.from_iterable(seats)),
    )
    joined_combinations = map(lambda t: "".join(t), combinations)
    list(joined_combinations)
    # returns
    ['A1a', 'A1b', 'A1a', 'A1b', 'A1c', 'A1d', 'A1a', ...]
    

    Explanation: Applying two times chain.from_iterable you can "unpack" individual characters from the nested lists, then creating the product of the items of the unnested lists (which creates 3-tuples) and finally join the items of each 3-tuple together.
    If you want to avoid duplicates you can put a set() around each argument in the product.