簡體   English   中英

從列表中生成所有可能的組合

[英]Generating all possible combinations from a list of lists

我有以下列表:

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

此列表代表一個難題的小世界。 在此示例中,世界包含4堆彼此堆疊的物體。 我只能移動頂部對象並將其放在其他堆棧的頂部。 字母表示對象的類型,例如a可能是岩石和ba球。 我需要生成此微型世界可能存在的所有可能狀態。 我試圖在python中做到這一點,但不知道如何實現它。

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

您可以使用遞歸生成器執行此操作。 邏輯如下所示:

  • 產生當前狀態
  • 找到所有遠離該狀態的狀態
  • 遞歸地將邏輯應用於那些

這有一個問題:有可能回到起點(將'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)

請注意,Python 2.7中不存在yield from ,但是如果您不建議至少升級到3.3,則可以將其替換為循環:

for new_state in shuffle_stacks(next_state):
     yield new_state

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM