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