Python 中使用 itertools 的不同长度列表的产品

product of different length list using itertools in Python

我有以下列表:

sectors = ["A", "B"]

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

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

并且我想创建类似 A1a, A1b, A2a, A2b, A2c ...

的产品

此代码

  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))

将所需结果打印为 A1a A1b A2a A2b A2c A2d A3a ...

能不能用更好更易读的方式解决这个问题,我正在练习itertools,这让我有点困惑。

不确定这是您想要的还是更优雅:

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', ...]

说明:应用两次 chain.from_iterable 您可以从嵌套列表中“解包”单个字符,然后创建非嵌套列表项的乘积(创建 3 元组),最后加入项每个三元组在一起。
如果你想避免重复,你可以在 product.

中的每个参数周围放置一个 set()

由于您是从 3 个嵌套列表而不是笛卡尔积创建三元组,我认为 zip 相应的子列表并使用循环可能更直观。

out = [sector + row + s for sector, rws, sts in zip(sectors, rows, seats) 
       for row, seat in zip(rws, sts) for s in seat] 

如果我们想使用itertools.product,首先重复sectors中的元素以匹配其他列表的子列表的长度,而不是像在最内层循环中那样手动创建产品元素上面,我们迭代了产品本身。当然,这很像你自己的做法。

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)]

输出:

['A1a', 'A1b', 'A2a', 'A2b', 'A2c', 'A2d', 'A3a', 'A3b', 'B1a', 'B1b', 'B2a', 'B2b', 'B2c', 'B2d', 'B3a', 'B3b', 'B4a', 'B4b', 'B4c', 'B4d']