[英]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.