生成列表的所有可能组合,“itertools.combinations”会遗漏一些结果

Posted

技术标签:

【中文标题】生成列表的所有可能组合,“itertools.combinations”会遗漏一些结果【英文标题】:Generating all possible combinations of a list, "itertools.combinations" misses some results 【发布时间】:2013-06-30 07:42:45 【问题描述】:

给定 Python 中的项目列表,我如何获得项目的所有可能组合?

这个网站上有几个类似的问题,建议使用itertools.combinations,但只返回我需要的子集:

stuff = [1, 2, 3]
for L in range(0, len(stuff)+1):
    for subset in itertools.combinations(stuff, L):
        print(subset)

()
(1,)
(2,)
(3,)
(1, 2)
(1, 3)
(2, 3)
(1, 2, 3)

如您所见,它仅返回严格顺序的项目,不返回 (2, 1)(3, 2)(3, 1)(2, 1, 3)(3, 1, 2)(2, 3, 1)(3, 2, 1)。有什么解决方法吗?我好像什么都想不出来。

【问题讨论】:

组合中的顺序无所谓,(2, 1) 和(1, 2)一样 好问题。虽然从技术上讲,您可以编写自己的函数来获得这些组合。 【参考方案1】:

使用itertools.permutations:

>>> import itertools
>>> stuff = [1, 2, 3]
>>> for L in range(0, len(stuff)+1):
        for subset in itertools.permutations(stuff, L):
                print(subset)
...         
()
(1,)
(2,)
(3,)
(1, 2)
(1, 3)
(2, 1)
(2, 3)
(3, 1)
....

求助itertools.permutations:

permutations(iterable[, r]) --> permutations object

Return successive r-length permutations of elements in the iterable.

permutations(range(3), 2) --> (0,1), (0,2), (1,0), (1,2), (2,0), (2,1)

【讨论】:

【参考方案2】:

您可以使用这个简单的代码在python中生成列表的所有组合

import itertools

a = [1,2,3,4]
for i in xrange(1,len(a)+1):
   print list(itertools.combinations(a,i))

结果:

[(1,), (2,), (3,), (4,)]
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
[(1, 2, 3, 4)]

【讨论】:

要求在结果中查看 (2, 1) 的问题。您的答案中的 (2, 1) 在哪里? 组合 (2, 1) 和 (1, 2) 都是同一个家伙。 尽管问题中有“组合”,但它的意思是排列。读到最后,发现 (2, 1) 和 (1, 2) 都是 OP 所期望的。【参考方案3】:

您是在寻找itertools.permutations 吗?

来自help(itertools.permutations)

Help on class permutations in module itertools:

class permutations(__builtin__.object)
 |  permutations(iterable[, r]) --> permutations object
 |  
 |  Return successive r-length permutations of elements in the iterable.
 |  
 |  permutations(range(3), 2) --> (0,1), (0,2), (1,0), (1,2), (2,0), (2,1)

示例代码:

>>> from itertools import permutations
>>> stuff = [1, 2, 3]
>>> for i in range(0, len(stuff)+1):
        for subset in permutations(stuff, i):
               print(subset)


()
(1,)
(2,)
(3,)
(1, 2)
(1, 3)
(2, 1)
(2, 3)
(3, 1)
(3, 2)
(1, 2, 3)
(1, 3, 2)
(2, 1, 3)
(2, 3, 1)
(3, 1, 2)
(3, 2, 1)

来自***,排列组合的区别:

排列:

非正式地,一组对象的排列是这些对象按特定顺序排列。例如,集合1,2,3有六个排列,分别是(1,2,3), (1,3,2), (2,1,3), (2,3,1) , (3,1,2) 和 (3,2,1)。

组合:

在数学中,组合是从一个更大的组中选择多个事物的一种方式,其中(与排列不同)顺序无关紧要。

【讨论】:

【参考方案4】:

itertools.permutations 将是您想要的。根据数学定义,combinations 的顺序无关紧要,这意味着(1,2) 被认为与(2,1) 相同。而对于permutations,每个不同的排序都算作一个唯一的排列,所以(1,2)(2,1) 是完全不同的。

【讨论】:

【参考方案5】:

这里是没有 itertools 的解决方案

首先让我们定义01s的指示向量与子列表(1如果项目在子列表中)之间的转换

def indicators2sublist(indicators,arr):
   return [item for item,indicator in zip(arr,indicators) if int(indicator)==1]

接下来,定义一个从02^n-1 之间的数字到其二进制向量表示的映射(使用字符串的format 函数):

def bin(n,sz):
   return ('d:0'+str(sz)+'b').format(d=n)

我们剩下要做的就是迭代所有可能的数字,然后调用indicators2sublist

def all_sublists(arr):
  sz=len(arr)
  for n in xrange(0,2**sz):
     b=bin(n,sz)
     yield indicators2sublist(b,arr)

【讨论】:

【参考方案6】:

我假设您希望所有可能的组合都作为值的“集合”。这是我编写的一段代码,可能有助于您了解一下:

def getAllCombinations(object_list):
    uniq_objs = set(object_list)
    combinations = []
    for obj in uniq_objs:
        for i in range(0,len(combinations)):
            combinations.append(combinations[i].union([obj]))
        combinations.append(set([obj]))
return combinations

这是一个示例:

combinations = getAllCombinations([20,10,30])
combinations.sort(key = lambda s: len(s))
print combinations
... [set([10]), set([20]), set([30]), set([10, 20]), set([10, 30]), set([20, 30]), set([10, 20, 30])]

我认为这有 n!时间复杂度,所以要小心。这可行,但可能不是最有效的

【讨论】:

【参考方案7】:

我只是想把它放在那里,因为我无法对每一个可能的结果都进行优化,并且请记住,当涉及到 python 时,我只有最原始的最基本知识,并且可能有一个更优雅的解决方案...... (也请原谅可怜的变量名

测试 = [1, 2, 3]

测试2= [0]

n = -1

def testingSomethingElse(number):

try:

    testing2[0:len(testing2)] == testing[0]

    n = -1

    testing2[number] += 1

except IndexError:

    testing2.append(testing[0])

当真时:

n += 1

testing2[0] = testing[n]

print(testing2)

if testing2[0] == testing[-1]:

    try:

        n = -1

        testing2[1] += 1

    except IndexError:

        testing2.append(testing[0])

    for i in range(len(testing2)):

        if testing2[i] == 4:

            testingSomethingElse(i+1)

            testing2[i] = testing[0]

我逃脱了 == 4 因为我正在使用整数,但您可能需要相应地修改它...

【讨论】:

以上是关于生成列表的所有可能组合,“itertools.combinations”会遗漏一些结果的主要内容,如果未能解决你的问题,请参考以下文章

在 Perl 中,如何生成列表的所有可能组合?

为字符串列表生成所有组合

Excel VBA 宏生成可能组合的列表

Python:生成列表的所有有序组合

值列表的所有可能组合

Matlab 生成所有可能的团队组合