【问题标题】:Find all combinations of a list with different elements removed each time查找每次删除不同元素的列表的所有组合
【发布时间】:2017-03-26 18:00:12
【问题描述】:

我需要一种方法来从两个不同的列表中找到所有组合,其中每个元素可能为空,也可能不为空。例如,对于这两个列表,我想调用一个返回所有这些组合列表的函数:

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.

【问题讨论】:

  • 我不清楚从输入到输出的逻辑是什么,但我建议你看看itertools
  • 所以您想遍历b 的组合并从a 中删除这些?
  • a = ['A','A']b = ['A'][] 是一个有效的结果:它会导致删除元素 multiple 次吗?此外,b 的订购方式是否与a 相同?如果a = ['A','S','B']b = ['B',A'] 会发生什么?
  • 第一个例子不应该也输出['A']['B']
  • @JuanT:根据标题和我的理解,生成b 的组合并删除 a...

标签: python list python-3.x combinations


【解决方案1】:

我假设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 转换成一个集合来提升性能。这严格来说是没有必要的。然后我们使用递归算法,其中对于a 中的每个元素a[i],即b,我们有一个决定点是否将其包含在结果中(这就是为什么我们在该元素时再次执行递归弹出)。当我们到达列表末尾时,我们将运行列表l 转换为tuple(..)。您也可以使用list(..) 将其转换为列表。

我们使用运行列表来稍微提高性能,因为连接两个列表在 O(n) 中完成,而运行列表可以在 O(1 ) 摊销成本。

这将产生一个 tuples 的生成器。您可以使用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',)]

如果需要lists,您可以使用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']]

【讨论】:

  • 太棒了!在我拥有的一些测试数据上完美运行。 +1
【解决方案2】:

在玩了之后,我找到了 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']]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-21
    • 1970-01-01
    • 1970-01-01
    • 2017-04-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多