繁体   English   中英

查找列表的所有组合,每次都删除不同的元素

[英]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转换为集合以提高性能。 严格来说,这是没有必要的。 然后,我们使用递归算法,其中对于ba中的每个元素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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM