[英]Find all combinations of a list with different elements removed each time
我需要一種從兩個不同的列表中查找所有組合的方法,其中每個元素可以為null,也可以不為null。 例如,對於兩個列表,我想調用一個函數,該函數返回所有這些組合的列表:
a = ['A', 'S', 'B']
b = ['A', 'B']
find_combinations(a, b)
應該返回:
[['A', 'S', 'B'], ['A', 'S'], ['S', 'B'], ['S']]
我可以做這個簡單的例子,但是如果列表更復雜,例如['A', 'B', 'S', 'A', 'A']
那么可能的選項就復雜得多:
[['A', 'B', 'S', 'A', 'A'],
['A', 'B', 'S', 'A'],
['A', 'B', 'S', 'A'],
['B', 'S', 'A', 'A']
... etc.
我將假設b
的元素是可哈希的 。 在這種情況下,您可以使用以下代碼:
def without(a,i,bi,l):
if i >= len(a):
yield tuple(l)
else:
l.append(a[i])
for result in without(a,i+1,bi,l):
yield result
l.pop()
if a[i] in bi:
for result in without(a,i+1,bi,l):
yield result
def find_combinations(a, b):
for result in without(a,0,set(b),[]):
yield result
在這里,我們首先將b
轉換為集合以提高性能。 嚴格來說,這是沒有必要的。 然后,我們使用遞歸算法,其中對於b
中a
中的每個元素a[i]
,我們都有一個決策點,是否將其包括在結果中(這就是為什么當該元素彈出時我們再次執行遞歸) 。 當我們到達列表的末尾時,我們將運行列表l
轉換為tuple(..)
。 您還可以使用list(..)
將其轉換為列表。
我們使用運行列表來提高性能,因為將兩個列表連接在一起是在O(n)中完成的,而運行列表可以在O(1)攤銷成本中append(..)
和pop(..)
。
這將產生一個tuple
s的生成器 。 您可以使用list(..)
實現每個生成器的結果,例如:
>>> list(find_combinations(['A','S','B'],['A','B']))
[('A', 'S', 'B'), ('A', 'S'), ('S', 'B'), ('S',)]
>>> list(find_combinations(['A', 'B', 'S', 'A', 'A'],['A','B']))
[('A', 'B', 'S', 'A', 'A'), ('A', 'B', 'S', 'A'), ('A', 'B', 'S', 'A'), ('A', 'B', 'S'), ('A', 'S', 'A', 'A'), ('A', 'S', 'A'), ('A', 'S', 'A'), ('A', 'S'), ('B', 'S', 'A', 'A'), ('B', 'S', 'A'), ('B', 'S', 'A'), ('B', 'S'), ('S', 'A', 'A'), ('S', 'A'), ('S', 'A'), ('S',)]
如果list
是必需的S,你可以使用map(list,..)
將它們轉換成列表,如:
>>> list(map(list,find_combinations(['A','S','B'],['A','B'])))
[['A', 'S', 'B'], ['A', 'S'], ['S', 'B'], ['S']]
>>> list(map(list,find_combinations(['A', 'B', 'S', 'A', 'A'],['A','B'])))
[['A', 'B', 'S', 'A', 'A'], ['A', 'B', 'S', 'A'], ['A', 'B', 'S', 'A'], ['A', 'B', 'S'], ['A', 'S', 'A', 'A'], ['A', 'S', 'A'], ['A', 'S', 'A'], ['A', 'S'], ['B', 'S', 'A', 'A'], ['B', 'S', 'A'], ['B', 'S', 'A'], ['B', 'S'], ['S', 'A', 'A'], ['S', 'A'], ['S', 'A'], ['S']]
玩耍后,我找到了威廉·范·昂森(Willem Van Onsem)答案的另一種方法。 不太干凈,但也可以。
def empty_derivations(rule, empty_list):
returned = []
returned.append(rule)
for element in returned:
for num, char in enumerate(element):
temp = element[:]
if char in empty_list:
del temp[num]
returned.append(temp)
return_list = []
for element in returned:
if element not in return_list:
return_list.append(element)
return return_list
調用時給出:
>>> a = empty_derivations(['A', 'B', 'S', 'A', 'A'], ['A', 'B'])
>>> print(a)
[['A', 'B', 'S', 'A', 'A'],
['B', 'S', 'A', 'A'],
['A', 'S', 'A', 'A'],
['A', 'B', 'S', 'A'],
['S', 'A', 'A'],
['B', 'S', 'A'],
['A', 'S', 'A'],
['A', 'B', 'S'],
['S', 'A'],
['B', 'S'],
['A', 'S'],
['S']]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.