我正在尝试在python中使用一些约束在2个列表A和B之间生成所有可能的组合。 A和B交替选择值,A始终优先选择。 A和B可能有重叠值。如果A已经选择了一个值,则B无法选择它,反之亦然。
两个列表的长度不必相等。如果一个列表没有可用值可供选择,那么我将停止生成组合
每个元素选择的元素也必须按升序排列,即A[1] < A[2] < .... A[n]
和B[1] < B[2] < .... B[n]
,其中A[i]
和B[i]
是第i
个元素分别由A和B
示例:
A = [1, 2, 3, 4]
B = [2, 5]
我需要的解决方案是
(1), (2), (3), (4),
(1,2), (1,5), (2,5), (3,2), (3,5), (4,2), (4,5),
(1,2,3), (1,2,4), (3,2,4), (1,5,2), (1,5,3), (1,5,4), (2,5,3), (2,5,4), (3,5,4),
(1,2,3,5), (1,2,4,5), (3,2,4,5)
(1,2,3,5,4)
我相信python中的itertools可能对此有用,但是我还没有真正弄清楚如何在这种情况下实现它。
到目前为止,这就是我的解决方法:
A = [1, 2, 3, 4]
B = [2, 5]
A_set = set(A)
B_set = set(b)
#Append both sets
C = A.union(B)
for L in range(len(C), 0, -1):
for subset in itertools.combinations(C, L):
#Check if subset meets constraints and print it if it does
答案 0 :(得分:0)
如注释中所述,这可能太具体了,无法使用itertools轻松解决,而应该使用递归(生成器)函数。只需从轮到的列表中选择一个下一个元素,跟踪已选择的元素,然后再次递归调用该函数,交换并缩短列表并将该元素添加到所选元素的集合中,直到获得所需的元素为止数字。
类似的事情(可以通过在两个列表中为当前索引添加参数,而不是为递归调用实际划分列表来改进此方法):
def solve(n, lst1, lst2, selected):
if n == 0:
yield []
elif lst1:
for i, x in enumerate(lst1):
if x not in selected:
selected.add(x)
for rest in solve(n-1, lst2, lst1[i+1:], selected):
yield [x] + rest
selected.remove(x)
或更简洁:
def solve(n, lst1, lst2, selected):
if n == 0:
yield []
elif lst1:
yield from ([x] + rest for i, x in enumerate(lst1) if x not in selected
for rest in solve(n-1, lst2, lst1[i+1:], selected.union({x})))
示例:
A = [1, 2, 3, 4]
B = [2, 5]
result = [res for n in range(1, len(A)+len(B)+1) for res in solve(n, A, B, set())]
然后,result
是:
[[1], [2], [3], [4],
[1, 2], [1, 5], [2, 5], [3, 2], [3, 5], [4, 2], [4, 5],
[1, 2, 3], [1, 2, 4], [1, 5, 2], [1, 5, 3], [1, 5, 4], [2, 5, 3], [2, 5, 4], [3, 2, 4], [3, 5, 4],
[1, 2, 3, 5], [1, 2, 4, 5], [3, 2, 4, 5],
[1, 2, 3, 5, 4]]