列表列表的所有组合

时间:2009-04-28 16:44:48

标签: python combinations

我基本上在寻找Combination of List<List<int>>

的python版本

鉴于列表清单,我需要一个新列表,列出列表之间所有可能的项目组合。

[[1,2,3],[4,5,6],[7,8,9,10]] -> [[1,4,7],[1,4,8],...,[3,6,10]]

列表的数量未知,因此我需要适用于所有情况的内容。优雅的奖励点!

9 个答案:

答案 0 :(得分:342)

您需要itertools.product

>>> import itertools
>>> a = [[1,2,3],[4,5,6],[7,8,9,10]]
>>> list(itertools.product(*a))
[(1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 4, 10), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 5, 10), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 6, 10), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 4, 10), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 5, 10), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 6, 10), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 4, 10), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 5, 10), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 6, 10)]

答案 1 :(得分:23)

最优雅的解决方案是在python 2.6中使用itertools.product

如果你没有使用Python 2.6,那么itertools.product的文档实际上显示了一个等效的函数来以“手动”的方式来完成产品:

def product(*args, **kwds):
    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
    # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
    pools = map(tuple, args) * kwds.get('repeat', 1)
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield tuple(prod)

答案 2 :(得分:18)

listOLists = [[1,2,3],[4,5,6],[7,8,9,10]]
for list in itertools.product(*listOLists):
  print list;

我希望你能发现我第一次遇到它时的优雅。

答案 3 :(得分:3)

Numpy可以做到:

 >>> import numpy
 >>> a = [[1,2,3],[4,5,6],[7,8,9,10]]
 >>> [list(x) for x in numpy.array(numpy.meshgrid(*a)).T.reshape(-1,len(a))]
[[ 1, 4, 7], [1, 5, 7], [1, 6, 7], ....]

答案 4 :(得分:3)

此任务的直接递归没有错,如果您需要一个适用于字符串的版本,这可能符合您的需求:

combinations = []

def combine(terms, accum):
    last = (len(terms) == 1)
    n = len(terms[0])
    for i in range(n):
        item = accum + terms[0][i]
        if last:
            combinations.append(item)
        else:
            combine(terms[1:], item)


>>> a = [['ab','cd','ef'],['12','34','56']]
>>> combine(a, '')
>>> print(combinations)
['ab12', 'ab34', 'ab56', 'cd12', 'cd34', 'cd56', 'ef12', 'ef34', 'ef56']

答案 5 :(得分:1)

一个人可以为此使用基本的python:

L = [[1,2,3],[4,5,6],[7,8,9,10]]

prod = 1
for sublist in L:   prod *= len(sublist)  # find how many combinations will be there (product of lengths of sublists)
outlist = [[] for i in range(prod)]       # create a list of empty lists for combinations
for sublist in L:                         # for each sublist
    oi=0; sli=0                           # indices for outlist and sublist
    while oi < len(outlist):
        outlist[oi].append(sublist[sli])  # add its items to different combination lists
        oi += 1; sli += 1
        if sli >= len(sublist): sli = 0   # recycle the items
print(outlist)

输出:

[[1, 4, 7], [2, 5, 8], [3, 6, 9], [1, 4, 10], [2, 5, 7], [3, 6, 8], [1, 4, 9], [2, 5, 10], [3, 6, 7], [1, 4, 8], [2, 5, 9], [3, 6, 10], [1, 4, 7], [2, 5, 8], [3, 6, 9], [1, 4, 10], [2, 5, 7], [3, 6, 8], [1, 4, 9], [2, 5, 10], [3, 6, 7], [1, 4, 8], [2, 5, 9], [3, 6, 10], [1, 4, 7], [2, 5, 8], [3, 6, 9], [1, 4, 10], [2, 5, 7], [3, 6, 8], [1, 4, 9], [2, 5, 10], [3, 6, 7], [1, 4, 8], [2, 5, 9], [3, 6, 10]]

答案 6 :(得分:0)

from itertools import product 
list_vals = [['Brand Acronym:CBIQ', 'Brand Acronym :KMEFIC'],['Brand Country:DXB','Brand Country:BH']]
list(product(*list_vals))

输出:

  

[('品牌缩写:CBIQ','Brand Country:DXB'),
      (“品牌缩写:CBIQ”,“品牌国家:BH”),
      (“品牌缩写:KMEFIC”,“品牌国家:DXB”),
      (“品牌缩写:KMEFIC”,“品牌国家:BH”)]

答案 7 :(得分:0)

这主要是模仿使用 Answer by Jarret Hardieitertools.product 之类的解决方案,但有以下区别:

  • 这将参数传递给 itertools.product 内联,而不是通过变量 a - 因此内联参数不需要 *args 语法
  • 如果您的 mypy type-linter 表现得像我的一样,并且您可以让您的代码以带有内联 *args 参数(例如 product)的 product(*[[1,2,3],[4,5,6],[7,8,9,10]]) 语法“工作”, mypy 可能仍会失败(例如 error: No overload variant of "product" matches argument type "List[object]"
  • 因此,mypy 的解决方案是不使用 *args 语法,如下所示:
    >>> import itertools
    >>> list(itertools.product([1,2,3],[4,5,6],[7,8,9,10]))
    [(1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 4, 10), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 5, 10), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 6, 10), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 4, 10), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 5, 10), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 6, 10), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 4, 10), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 5, 10), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 6, 10)]

答案 8 :(得分:0)

这个答案不像使用 itertools 那样简洁,但这些想法可能很有用。

从 zip() here 的构造中汲取灵感,我们可以执行以下操作。

>>> a = iter([[1,2,3],[4,5,6],[7,8,9,10]])
>>> sentinel = object()
>>> result = [[]]
>>> while True:
>>>     l = next(a,sentinel)
>>>     if l == sentinel:
>>>         break
>>>     result = [ r + [digit] for r in result for digit in l]
>>> print(result)
[[1, 4, 7], [1, 4, 8], [1, 4, 9], [1, 4, 10], [1, 5, 7], [1, 5, 8], [1, 5, 9], [1, 5, 10], [1, 6, 7], [1, 6, 8], [1, 6, 9], [1, 6, 10], [2, 4, 7], [2, 4, 8], [2, 4, 9], [2, 4, 10], [2, 5, 7], [2, 5, 8], [2, 5, 9], [2, 5, 10], [2, 6, 7], [2, 6, 8], [2, 6, 9], [2, 6, 10], [3, 4, 7], [3, 4, 8], [3, 4, 9], [3, 4, 10], [3, 5, 7], [3, 5, 8], [3, 5, 9], [3, 5, 10], [3, 6, 7], [3, 6, 8], [3, 6, 9], [3, 6, 10]]

我们使用 a 作为迭代器,以便连续获得它的下一项,而无需知道有多少先验。当我们用完 next 中的列表时,sentinel 命令将输出 a(这是一个专门为进行此比较而创建的对象,请参阅 here 以获得一些解释),导致触发 if 语句,以便我们跳出循环。