【问题标题】:Generating all possible combinations from a list of lists从列表列表中生成所有可能的组合
【发布时间】:2014-03-22 08:54:47
【问题描述】:

我有以下列表:

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

这个列表代表了一个谜题中的迷你世界。在此示例中,世界包含 4 堆相互堆叠的对象。我只能移动顶部对象并将其放在其他堆栈的顶部。字母代表一种对象,例如 a 可能是石头,b 可能是球。 我需要为这个迷你世界生成所有可能存在的状态。我试图在 python 中做到这一点,但不知道如何实现它。

【问题讨论】:

  • 你有多个相同类型的对象。您需要区分单个对象还是仅区分对象类型?
  • 个别对象很重要。
  • 对于[ [a], [b], [] ]的情况,可能的状态是什么?您是否正在尝试“使用可用移动从当前状态中找到所有有效状态”?然后你需要清楚地定义什么是可用的移动,以及你如何表示堆栈(它是表示为从上到下还是从下到上的列表?)

标签: python algorithm python-2.7 artificial-intelligence


【解决方案1】:

您可以将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')]]

【讨论】:

  • 我认为不太正确。最小的情况是两堆,每堆有一个物品。 [[a],[b]],现在这个世界上所有可以存在的状态如下:[([a],[b]),([b,a],[]),([],[ a,b])].
【解决方案2】:

您可以使用递归生成器来做到这一点。逻辑是这样的:

  • 产生当前状态
  • 找出所有离这个状态一步之遥的状态
  • 递归地将逻辑应用于那些

这样做有一个问题:有可能回到起点(将'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)

请注意,yield from 在 Python 2.7 中不存在,但如果升级到至少 3.3 不适合您,您可以用循环替换它:

for new_state in shuffle_stacks(next_state):
     yield new_state

【讨论】:

  • 非常感谢!这行得通。将尝试扩展它并发布我的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-14
  • 2017-08-13
  • 1970-01-01
  • 2012-05-05
  • 2023-03-29
相关资源
最近更新 更多