使用itertools从列表中进行组合

时间:2016-09-15 20:32:10

标签: python list combinations itertools

import itertools
a = [[2, 3], [3, 4]]
b = [[5, 6], [7, 8], [9, 10]]
c = [[11, 12], [13, 14]]
d = [[15, 16], [17, 18]]
e = [[12,16],[13,17],[14,18],[15,19]]

q=[]
q=list(itertools.combinations((a, b, b,c, c, d,e),7)
print q

如何正确使用itertools中的组合功能一次使用列表,b无需替换2次,c次无需替换,d和e各使用一次?

[[[2, 3],[5, 6],[7, 8],[11, 12],[13, 14],[15, 16],[12,16]], 
[[2, 3],[5, 6],[7, 8],[11, 12],[13, 14],[15, 16],[13,17]],
[[2, 3],[5, 6],[7, 8],[11, 12],[13, 14],[15, 16],[14,18]],
[[2, 3],[5, 6],[7, 8],[11, 12],[13, 14],[15, 16],[15,19]], 
[[2, 3],[5, 6],[7, 8],[11, 12],[13, 14],[15, 16],[12,16]],...
[[3, 4],[7, 8],[9, 10],[11, 12], [13, 14],[17, 18],[15,19]]]

3 个答案:

答案 0 :(得分:2)

您好像正在寻找combinationsproduct的组合:使用combinations获取可能的组合而无需替换重复列表,然后使用product结合所有这些组合。您可以将列表和计数放在两个列表中,zip这些列表,并使用生成器表达式来获取所有组合。

from itertools import product, combinations, chain
lists = [a,b,c,d,e]
counts = [1,2,2,1,1]
combs = product(*(combinations(l, c) for l, c in zip(lists, counts)))

对于此示例,combs生成器包含48个元素,其中包括:

[(([2, 3],), ([5, 6], [7, 8]), ([11, 12], [13, 14]), ([15, 16],), ([12, 16],)),
 ...
 (([2, 3],), ([5, 6], [7, 8]), ([11, 12], [13, 14]), ([17, 18],), ([15, 19],)),
 (([2, 3],), ([5, 6], [9, 10]),([11, 12], [13, 14]), ([15, 16],), ([12, 16],)),
 ...
 (([3, 4],), ([5, 6], [7, 8]), ([11, 12], [13, 14]), ([15, 16],), ([12, 16],)),
 ...
 (([3, 4],), ([5, 6], [7, 8]), ([11, 12], [13, 14]), ([17, 18],), ([15, 19],)),
 ...
 (([3, 4],), ([7, 8], [9, 10]),([11, 12], [13, 14]), ([17, 18],), ([15, 19],))]

如果您想要flattened lists,只需chain他们:

>>> combs = (list(chain(*p)) for p in product(*(combinations(l, c) for l, c in zip(lists, counts))))
>>> list(combs)
[[[2, 3], [5, 6], [7, 8], [11, 12], [13, 14], [15, 16], [12, 16]],
 ...
 [[3, 4], [7, 8], [9, 10], [11, 12], [13, 14], [17, 18], [15, 19]]]

答案 1 :(得分:1)

更新了预期输出的说明

You want itertools.product

itertools.product(a, b, b, c, c, c, c, d, e)

将在每次迭代中从每个参数中选择一个元素,将最右边的元素循环到最快,最左边的最慢。

你可以使用扩展参数解包来在Python 3中更明显地表达某些参数的重复:

itertools.product(a, *[b]*2, *[c]*4, d, e)

或者使用tobias_k's solution来更一般地重复序列(这也适用于Py2)。

答案 2 :(得分:1)

您要实现的目标是Cartesian product of input iterables,而不是列表中项目的组合。因此,您必须改为使用itertools.product()

如果在不止一次使用的列表中允许重复,则答案很简单:

>>> import itertools
>>> a = [1,2]
>>> b = [3,4]
>>> [i for i in itertools.product(a, b, b)]
[(1, 3, 3), (1, 3, 4), (1, 4, 3), (1, 4, 4), (2, 3, 3), (2, 3, 4), (2, 4, 3), (2, 4, 4)]

但是如果在同一个列表中repetition is not allowed,则会变得有点讨厌,您需要将上述答案与combinations()chain()结合起来(与{{3}提到的相同) })。此代码将提供所有combinations的列表:

>>> from itertools import chain, product, combinations
>>> lists, counts = [a, b], [1, 2]  # to track that a is to be used once, and b twice
>>> list(list(chain(*p)) for p in product(*(combinations(l, c) for l, c in zip(lists, counts))))
[[1, 3, 4], [2, 3, 4]]

但是,如果您需要排列而不是组合,则必须使用tobias_k更新上述代码:

>>> from itertools import chain, product, permutations
>>> list(list(chain(*p)) for p in product(*(permutations(l, c) for l, c in zip(lists, counts))))
[[1, 3, 4], [1, 4, 3], [2, 3, 4], [2, 4, 3]]