生成2个列表的所有组合(游戏)

时间:2018-10-18 22:05:40

标签: python itertools

我正在尝试在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

1 个答案:

答案 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]]