从具有重复元素的列表中获取所有可能的组合?

时间:2018-05-06 13:44:18

标签: python combinations

我有重复元素的列表,例如array = [2,2,2,7]

如果我使用建议的in this answer解决方案(使用itertools.combinations()),我会得到:

()
(7,)
(2,)
(2,)
(2,)
(7, 2)
(7, 2)
(7, 2)
(2, 2)
(2, 2)
(2, 2)
(7, 2, 2)
(7, 2, 2)
(7, 2, 2)
(2, 2, 2)
(7, 2, 2, 2)

正如您可以看到一些'组合'重复,例如(7,2,2)出现了3次。

我想要的输出是:

()
(7,)
(2,)
(7, 2)
(2, 2)
(7, 2, 2)
(2, 2, 2)
(7, 2, 2, 2)

我可以检查重复组合的输出,但我不觉得这是解决这个问题的最佳方法。

3 个答案:

答案 0 :(得分:4)

您可以获取组合的集合,然后将它们链接在一起。

from itertools import chain, combinations

arr = [2, 2, 2, 7]

list(chain.from_iterable(set(combinations(arr, i)) for i in range(len(arr) + 1)))
# [(), (7,), (2,), (2, 7), (2, 2), (2, 2, 2), (2, 2, 7), (2, 2, 2, 7)]

答案 1 :(得分:2)

您需要维护一组以相同方式排序的元组:

import itertools as it 

desired=set([(),(7,),(2,),(7, 2),(2, 2),(7, 2, 2),(2, 2, 2),(7, 2, 2, 2)])
result=set()
for i in range(len(array)+1):
    for combo in it.combinations(array, i):
        result.add(tuple(sorted(combo, reverse=True)))

>>> result==desired
True

答案 2 :(得分:1)

不使用itertools.combinations()set

from collections import Counter
import itertools

def powerset(bag):
    for v in itertools.product(*(range(r + 1) for r in bag.values())):
        yield Counter(zip(bag.keys(), v))

array = [2, 2, 2, 7]

for s in powerset(Counter(array)):
    # Convert `Counter` object back to a list
    s = list(itertools.chain.from_iterable(itertools.repeat(*mv) for mv in s))
    print(s)

我认为您的问题可以替代地说是找到多重集的权力集,至少根据this definition

但值得注意的是,上面显示的方法会慢于其他答案中的解决方案,例如this one只会将itertools.combinations()的结果分组到set以删除重复项,尽管看起来效率较低,但实际上它仍然更快,因为在Python中迭代比在C中慢得多(参见itertoolsmodule.c实现itertools.combinations())。

通过我的有限测试,当你的数组中有大约14个不同的元素时,这个答案中显示的方法将优于前面提到的方法,每个元素的平均多重性为2(此时另一种方法开始消失,运行速度慢很多倍,但是在这种情况下,任何一种方法的运行时间都不超过30秒,因此如果考虑性能,那么您可能需要考虑在C中实现应用程序的这一部分。