制作列表的所有可能组合

Posted

技术标签:

【中文标题】制作列表的所有可能组合【英文标题】:Making all possible combinations of a list 【发布时间】:2012-01-12 09:37:12 【问题描述】:

我需要能够制作一个包含输入列表的所有可能组合的列表。 例如列表[1,2,3] 应该返回[1 [1,2] [1,3] 2 [2,3] 3 [1,2,3]] 该列表不必按任何特定顺序排列。在这个网站上,我发现了很多使用 itertools 的函数,但是当我只需要 list 时,这些函数会返回对象。

【问题讨论】:

这能回答你的问题吗? How to get all possible combinations of a list’s elements? 【参考方案1】:

只需使用itertools.combinations。例如:

import itertools

lst = [1, 2, 3]
combs = []

for i in xrange(1, len(lst)+1):
    combs.append(i)
    els = [list(x) for x in itertools.combinations(lst, i)]
    combs.append(els)

现在combs 持有这个值:

[1, [[1], [2], [3]], 2, [[1, 2], [1, 3], [2, 3]], 3, [[1, 2, 3]]]

是的,它与您提供的示例输出略有不同,但在该输出中您并未列出所有可能的组合。

我列出了组合的大小每个大小的实际列表之前,如果您需要的只是组合(没有大小,因为它显示在您的示例输出中)然后尝试这些其他版本的代码:

import itertools

lst = [1, 2, 3]
combs = []

for i in xrange(1, len(lst)+1):
    els = [list(x) for x in itertools.combinations(lst, i)]
    combs.extend(els)

现在combs 持有这个值:

[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

【讨论】:

这不是 OP 要求的。 @julio.alegria 是的,这就是 OP 的要求,我刚刚编辑了我的答案 效果很好,并且返回接近我正在寻找的东西。有什么方法可以获取列表列表而不是元组? @Charles,我刚刚编辑了我的答案,我相信这就是你要问的。不要让反对票愚弄你:) 他们是在之前我有时间扩展我的第一个答案 我不明白为什么@juliomalegria 否决了这个,非常粗鲁!答案一开始就不正确,但奥斯卡修正了答案,现在可以使用了。删除反对票。优雅简洁的解决方案! +1 :)【参考方案2】:

itertools 模块确实返回 generators 而不是列表,但是:

生成器通常比列表更有效(尤其是在您生成大量组合时) 当你真的需要时,你总是可以使用list(...)将生成器转换为列表。

itertoolschaincombinations 函数运行良好,但您需要使用Python 2.6 或更高版本:

import itertools

def all_combinations(any_list):
    return itertools.chain.from_iterable(
        itertools.combinations(any_list, i + 1)
        for i in xrange(len(any_list)))

然后你可以这样称呼它:

# as a generator
all_combinations([1,2,3])  # --> <itertools.chain at 0x10ef7ce10>

# as a list
list(all_combinations([1,2,3]))  # --> [(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

# as a list of lists
[list(l) for l in all_combinations([1,2,3])]  # --> [[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

如果您以前没有使用过生成器,请注意您循环遍历它们,就像它们是一个列表一样,例如:

# a generator returned instead of list
my_combinations = all_combinations([1,2,3])

# this would also work if `my_combinations` were a list
for c in my_combinations:
    print "Combo", c

"""
Prints:
  Combo (1,)
  Combo (2,)
  Combo (3,)
  Combo (1, 2)
  Combo (1, 3)
  Combo (2, 3)
  Combo (1, 2, 3)
"""

性能差异可能很大。如果您比较性能,您会发现生成器的创建速度要快得多:

# as a generator
all_combinations(range(25))  # timing: 100000 loops, best of 3: 2.53 µs per loop

# as a list
list(all_combinations(range(25)))  # timing: 1 loops, best of 3: 9.37 s per loop

请注意,在任何一种情况下,遍历所有组合仍然需要一些时间,但这对您来说可能是一个巨大的胜利,特别是如果您尽早找到所需的内容。

【讨论】:

这应该是公认的答案。它可能更难理解,但它是您将找到的最有效的生成器使用方法。大型列表的内存效率更高。【参考方案3】:

来自 itertools 模块的函数返回迭代器。将这些转换为列表所需要做的就是在结果上调用 list()

但是,由于您需要分别调用 itertools.combinations 三次(每个不同的长度一次),您可以使用 list.extend 将迭代器的所有元素添加到最终列表中。

尝试以下方法:

import itertools
in_list = [1, 2, 3]
out_list = []
for i in range(1, len(in_list)+1):
    out_list.extend(itertools.combinations(in_list, i))

或者作为列表理解:

out_list = [c for i in range(len(in_list)) for c in itertools.combinations(in_list, i+1)]

这些将产生以下列表:

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

如果您想要列表而不是元组,并且要将单个长度的元组转换为仅值,您可以执行以下操作:

out_list = [x[0] if len(x) == 1 else list(x) for x in out_list]
# [1, 2, 3, [1, 2], [1, 3], [2, 3], [1, 2, 3]]

或者将单个项目保留为列表:

out_list = map(list, out_list)

【讨论】:

我试过用这个,但解释器说我不能在 NoneTypes 上使用 iter。 您的两个解决方案仍然返回元组列表。 是的,我需要一个列表列表,而不是元组。有没有办法不使用 itertools 来解决问题? @Charles,您可以在没有 itertools 的情况下解决它,但它会更难。将元组转换为列表真的很容易,而且元组几乎与列表完全相同,所以我怀疑你真的需要这样做。如果您遇到错误,请向我们展示无效的代码。否则我们无法弄清楚你做错了什么。 @Charles - 编辑了我的代码,用于从元组转换为列表,以及将单长度元组转换为示例中的值。这可以在没有 itertools 的情况下完成,但不会那么简洁。【参考方案4】:

您可以在循环中使用itertools.combinations 来解决您的问题:

>>> l = [1,2,3]
>>> comb = []
>>> for i in range(len(l)):
...   comb += itertools.combinations(l,i+1)
... 
>>> comb
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

如果您希望它们作为列表:

>>> comb_list = [ list(t) for t in comb ]
>>> comb_list
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

编辑:组合的第一个参数是可迭代的,第二个参数是结果元组的长度(在本例中,从1len(l))。

更多关于组合:http://docs.python.org/library/itertools.html#itertools.combinations

【讨论】:

【参考方案5】:
l = [1,2,3]
combs = reduce(lambda x, y: list(itertools.combinations(l, y)) + x, range(len(l)+1), [])

如果你想要一个单线。

【讨论】:

【参考方案6】:

我认为值得将这里的其他答案归结为一个简单的 Python 3 示例:

from itertools import chain, combinations

def all_combinations(array):
    return chain(*(list(combinations(array, i + 1)) for i in range(len(array))))

这将返回一个可迭代的,以查看值:

>>> print(list(all_combinations((1, 2, 3))))
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

【讨论】:

以上是关于制作列表的所有可能组合的主要内容,如果未能解决你的问题,请参考以下文章

值列表的所有可能组合

如何获得多个列表的所有可能组合? [复制]

Hive UDF 从列表中生成所有可能的有序组合

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

列表迭代列表(所有可能的一个方向组合)

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