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 1:
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
.
Solution 2:
Since you're creating triples from 3 nested lists, not Cartesian product, I think it may be more intuitive to zip
the corresponding sublists and use a loop.
out = [sector + row + s for sector, rws, sts in zip(sectors, rows, seats)
for row, seat in zip(rws, sts) for s in seat]
If we want to use itertools.product
, first repeat elements in sectors
to match the lengths of sublists of the other lists and instead of creating the product elements manually like in the inner-most loop above, we iterate over the product itself. Of course, this is a lot like your own approach.
repsectors = [repeat(sector, len(rows[i])) for i, sector in enumerate(sectors)]
out = [''.join(x) for tpl1 in zip(repsectors, rows, seats)
for tpl2 in zip(*tpl1) for x in itertools.product(*tpl2)]
Output:
['A1a', 'A1b', 'A2a', 'A2b', 'A2c', 'A2d', 'A3a', 'A3b', 'B1a', 'B1b', 'B2a', 'B2b', 'B2c', 'B2d', 'B3a', 'B3b', 'B4a', 'B4b', 'B4c', 'B4d']