带有可选列表的笛卡尔积

Cartesian Product with optional lists

我正在 python 创建一个程序,它允许我根据给定的资产生成 NFT 艺术。 显然,可以生成的艺术数量根据资产(图层和图层图像)而变化,这正是问题所在,我如何计算可能的组合并计算可选图层?

更清楚:

例如我有4层:

l1 = ["A","B"]
l2 = ["C"]
l3 = ["D","E"] #optional
l4 = ["F","G"] #optional

其中 l3 和 l4 是可选的。所以我期望的组合是:

 1.  ["A","C"]
 2.  ["B","C"]
 3.  ["A","C","D"]
 4.  ["A","C","E"]
 5.  ["B","C","D"]
 6.  ["B","C","E"]
 7.  ["A","C","F"]
 8.  ["A","C","G"]
 9.  ["B","C","F"]
 10. ["B","C","G"]
 11. ["A","C","D","F"]
 12. ["A","C","D","G"]
 13. ["A","C","E","F"]
 14. ["A","C","E","G"]
 15. ["B","C","D","F"]
 16. ["B","C","D","G"]
 17. ["B","C","E","F"]
 18. ["B","C","E","G"]

我怎样才能做到这一点?我尝试使用 itertools.product 但显然它考虑了所有列表

我假设可选层的顺序很重要,因此您可以迭代创建可选层的所有组合,然后在 layers + optional_layers 上使用 itertools.product生成列表。

import itertools
from pprint import pprint

l1 = ["A","B"]
l2 = ["C"]
l3 = ["D","E"] #optional
l4 = ["F","G"] #optional

layers = [l1, l2]
optional_layers = [l3, l4]

results = []
results += itertools.product(*layers)
for i in range(len(optional_layers) + 1):
    comb = itertools.combinations(optional_layers, r=i)
    for c in comb:
        results += itertools.product(*layers, *c)

pprint(results)

输出

[('A', 'C'),
 ('B', 'C'),
 ('A', 'C'),
 ('B', 'C'),
 ('A', 'C', 'D'),
 ('A', 'C', 'E'),
 ('B', 'C', 'D'),
 ('B', 'C', 'E'),
 ('A', 'C', 'F'),
 ('A', 'C', 'G'),
 ('B', 'C', 'F'),
 ('B', 'C', 'G'),
 ('A', 'C', 'D', 'F'),
 ('A', 'C', 'D', 'G'),
 ('A', 'C', 'E', 'F'),
 ('A', 'C', 'E', 'G'),
 ('B', 'C', 'D', 'F'),
 ('B', 'C', 'D', 'G'),
 ('B', 'C', 'E', 'F'),
 ('B', 'C', 'E', 'G')]

一种方法是使用 itertools docs 中的 powerset 配方。将 'required lists' 的乘积与 'optional-list-set' 的每个子集链接在一起,生成一个生成每种可能性一次的生成器:

def powerset(iterable):
    """powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"""
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1))

def product_with_optional(required_sequences, optional_sequences):
    return chain.from_iterable(product(*required_sequences, *optionals)
                               for optionals in powerset(optional_sequences))

optional_combinations = product_with_optional(required_sequences=[l1, l2],
                                              optional_sequences=[l3, l4])

给出:

1 ('A', 'C')
2 ('B', 'C')
3 ('A', 'C', 'D')
4 ('A', 'C', 'E')
5 ('B', 'C', 'D')
6 ('B', 'C', 'E')
7 ('A', 'C', 'F')
8 ('A', 'C', 'G')
9 ('B', 'C', 'F')
10 ('B', 'C', 'G')
11 ('A', 'C', 'D', 'F')
12 ('A', 'C', 'D', 'G')
13 ('A', 'C', 'E', 'F')
14 ('A', 'C', 'E', 'G')
15 ('B', 'C', 'D', 'F')
16 ('B', 'C', 'D', 'G')
17 ('B', 'C', 'E', 'F')
18 ('B', 'C', 'E', 'G')