从列表列表生成所有可能的组合

时间:2014-03-22 08:54:47

标签: python algorithm python-2.7 artificial-intelligence

我有以下列表:

[[a,b,c],[b],[d,a,b,e],[a,c]]

此列表代表拼图问题中的迷你世界。在这个例子中,世界包含4堆堆叠在一起的物体。我只能移动顶部对象并将其放在其他堆栈的顶部。字母代表一种对象,例如可能是摇滚和b。 我需要为这个迷你世界生成所有可能存在的状态。我试图在python中这样做,但不知道如何实现它。

2 个答案:

答案 0 :(得分:0)

您可以将itertools.combinations_with_replacement与列表理解结合使用:

import itertools
ll = [['a','b','c'],['b'],['d','a','b','e'],['a','c']]
print [list(itertools.combinations_with_replacement(item,len(item))) for item in ll] 

它为列表列表中的每个元素提供组合。

输出:

 [[('a', 'a', 'a'), ('a', 'a', 'b'), ('a', 'a', 'c'), ('a', 'b', 'b'), ('a', 'b', 'c'), ('a', 'c', 'c'), ('b', 'b', 'b'), ('b', 'b', 'c'), ('b', 'c', 'c'), ('c', 'c', 'c')], 
 [('b',)], 
 [('d', 'd', 'd', 'd'), ('d', 'd', 'd', 'a'), ('d', 'd', 'd', 'b'), ('d', 'd', 'd', 'e'), ('d', 'd', 'a', 'a'), ('d', 'd', 'a', 'b'), ('d', 'd', 'a', 'e'), ('d', 'd', 'b', 'b'), ('d', 'd', 'b', 'e'), ('d', 'd', 'e', 'e'), ('d', 'a', 'a', 'a'), ('d', 'a', 'a', 'b'), ('d', 'a', 'a', 'e'), ('d', 'a', 'b', 'b'), ('d', 'a', 'b', 'e'), ('d', 'a', 'e', 'e'), ('d', 'b', 'b', 'b'), ('d', 'b', 'b', 'e'), ('d', 'b', 'e', 'e'), ('d', 'e', 'e', 'e'), ('a', 'a', 'a', 'a'), ('a', 'a', 'a', 'b'), ('a', 'a', 'a', 'e'), ('a', 'a', 'b', 'b'), ('a', 'a', 'b', 'e'), ('a', 'a', 'e', 'e'), ('a', 'b', 'b', 'b'), ('a', 'b', 'b', 'e'), ('a', 'b', 'e', 'e'), ('a', 'e', 'e', 'e'), ('b', 'b', 'b', 'b'), ('b', 'b', 'b', 'e'), ('b', 'b', 'e', 'e'), ('b', 'e', 'e', 'e'), ('e', 'e', 'e', 'e')], 
 [('a', 'a'), ('a', 'c'), ('c', 'c')]]

如果您想避免在组合中使用重复的相同元素,可以使用itertools.permutation

 [list(itertools.permutations(item,len(item))) for item in ll] 

输出:

[[('a', 'b', 'c'), ('a', 'c', 'b'), ('b', 'a', 'c'), ('b', 'c', 'a'), ('c', 'a', 'b'), ('c', 'b', 'a')], 
[('b',)], 
[('d', 'a', 'b', 'e'), ('d', 'a', 'e', 'b'), ('d', 'b', 'a', 'e'), ('d', 'b', 'e', 'a'), ('d', 'e', 'a', 'b'), ('d', 'e', 'b', 'a'), ('a', 'd', 'b', 'e'), ('a', 'd', 'e', 'b'), ('a', 'b', 'd', 'e'), ('a', 'b', 'e', 'd'), ('a', 'e', 'd', 'b'), ('a', 'e', 'b', 'd'), ('b', 'd', 'a', 'e'), ('b', 'd', 'e', 'a'), ('b', 'a', 'd', 'e'), ('b', 'a', 'e', 'd'), ('b', 'e', 'd', 'a'), ('b', 'e', 'a', 'd'), ('e', 'd', 'a', 'b'), ('e', 'd', 'b', 'a'), ('e', 'a', 'd', 'b'), ('e', 'a', 'b', 'd'), ('e', 'b', 'd', 'a'), ('e', 'b', 'a', 'd')], 
[('a', 'c'), ('c', 'a')]]

答案 1 :(得分:0)

您可以使用递归生成器执行此操作。逻辑的工作原理如下:

  • 产生当前状态
  • 找到所有离开此状态的状态
  • 以递归方式将逻辑应用于那些

这有一个问题:可以回到起点(移动' c'右边一个堆叠,然后移动' c'离开一个堆叠),会导致无限递归。我只考虑一个方向的移动来解决这个问题,但更一般的方法是跟踪你已经看过的所有状态,如果你回到一个状态就会挽救。

这就是我所拥有的:

def shuffle_stacks(state):
    '''
    shuffle_stacks([[a], [b, c]]) -> 
       [[a, b], [c]], 
       [[a], [c, b]], 
       [[], [c, b, a]]

    yield all possible states that can be given by moving an item off
    the top of a sublist to the top of any other sublist, recursively.

    Currently only moves items to the right of their starting point.

    '''
    yield state

    # Find all the possible states we can be in if we move
    # one item off the top of a stack to any stack to its right
    # Apply recursively to each such state

    for i, source in enumerate(state):
        unchanged_state = state[:i]
        targets = state[i+1:]
        source = source[:]

        if not source or not targets:
            continue

            item = source.pop()
            for j, target in enumerate(targets):
                # Copy mutables to isolate changes
                target = target[:]
                targets = targets[:]
                targets[j] = target

                target.append(item)
                next_state = unchanged_state + [source] + targets
                yield from shuffle_stacks(next_state)

请注意,{2.7}中不存在yield from,但如果升级到至少3.3不是您的选项,则可以将其替换为循环:

for new_state in shuffle_stacks(next_state):
     yield new_state