我需要能够创建一个包含输入列表中所有可能组合的列表。
例如,列表[1,2,3]
应返回[1 [1,2] [1,3] 2 [2,3] 3 [1,2,3]]
列表不必按任何特定顺序排列。在此站点上,我找到了很多使用itertools
的函数,但这些函数返回对象,而我只需要一个list
。
我需要能够创建一个包含输入列表中所有可能组合的列表。
例如,列表[1,2,3]
应返回[1 [1,2] [1,3] 2 [2,3] 3 [1,2,3]]
列表不必按任何特定顺序排列。在此站点上,我找到了很多使用itertools
的函数,但这些函数返回对象,而我只需要一个list
。
只需使用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]]
itertools
模块确实返回生成器而不是列表,但是:
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
请注意,在任何情况下,迭代所有组合仍需要一些时间,但如果您尽早找到所需内容,则可以获得很大的收益。
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)
您可以在循环内使用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]]
编辑:combinations函数的第一个参数是可迭代对象,第二个参数是生成元组的长度(在这个例子中从1
到len(l)
)。
更多关于combinations的信息:http://docs.python.org/library/itertools.html#itertools.combinations
l = [1,2,3]
combs = reduce(lambda x, y: list(itertools.combinations(l, y)) + x, range(len(l)+1), [])
我认为可以将其他答案简化成一个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)]