制作列表的所有可能组合
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(...)
将生成器转换为列表。
itertools
的chain
和combinations
函数运行良好,但您需要使用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]]
编辑:组合的第一个参数是可迭代的,第二个参数是结果元组的长度(在本例中,从1
到len(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)]
【讨论】:
以上是关于制作列表的所有可能组合的主要内容,如果未能解决你的问题,请参考以下文章