获得一系列列表的笛卡尔积?

我如何从一组列表中获得笛卡尔积(每个可能的值的组合)?

input:

somelists = [ [1, 2, 3], ['a', 'b'], [4, 5] ] 

期望的输出:

 [(1, 'a', 4), (1, 'a', 5), (1, 'b', 4), (1, 'b', 5), (2, 'a', 4), (2, 'a', 5) ...] 

在Python 2.6+

 import itertools for element in itertools.product(*somelists): print(element) 

文档: Python 3 – itertools.product

 import itertools >>> for i in itertools.product([1,2,3],['a','b'],[4,5]): ... print i ... (1, 'a', 4) (1, 'a', 5) (1, 'b', 4) (1, 'b', 5) (2, 'a', 4) (2, 'a', 5) (2, 'b', 4) (2, 'b', 5) (3, 'a', 4) (3, 'a', 5) (3, 'b', 4) (3, 'b', 5) >>> 

对于Python 2.5及更高版本:

 >>> [(a, b, c) for a in [1,2,3] for b in ['a','b'] for c in [4,5]] [(1, 'a', 4), (1, 'a', 5), (1, 'b', 4), (1, 'b', 5), (2, 'a', 4), (2, 'a', 5), (2, 'b', 4), (2, 'b', 5), (3, 'a', 4), (3, 'a', 5), (3, 'b', 4), (3, 'b', 5)] 

这是一个recursion版本的product() (只是一个例子):

 def product(*args): if not args: return iter(((),)) # yield tuple() return (items + (item,) for items in product(*args[:-1]) for item in args[-1]) 

例:

 >>> list(product([1,2,3], ['a','b'], [4,5])) [(1, 'a', 4), (1, 'a', 5), (1, 'b', 4), (1, 'b', 5), (2, 'a', 4), (2, 'a', 5), (2, 'b', 4), (2, 'b', 5), (3, 'a', 4), (3, 'a', 5), (3, 'b', 4), (3, 'b', 5)] >>> list(product([1,2,3])) [(1,), (2,), (3,)] >>> list(product([])) [] >>> list(product()) [()] 

与itertools.product :

 import itertools result = list(itertools.product(*somelists)) 

在Python 2.6及以上版本中,您可以使用“itertools.product”。 在旧版本的Python中,至less可以从文档中使用以下(几乎可以看到文档)的等效代码 :

 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) 

两者的结果是一个迭代器,所以如果你真的需要一个进一步处理的列表,使用list(result)

这是一个recursion生成器,它不存储任何临时列表

 def product(ar_list): if not ar_list: yield () else: for a in ar_list[0]: for prod in product(ar_list[1:]): yield (a,)+prod print list(product([[1,2],[3,4],[5,6]])) 

输出:

 [(1, 3, 5), (1, 3, 6), (1, 4, 5), (1, 4, 6), (2, 3, 5), (2, 3, 6), (2, 4, 5), (2, 4, 6)] 

我会用列表理解:

 somelists = [ [1, 2, 3], ['a', 'b'], [4, 5] ] cart_prod = [(a,b,c) for a in somelists[0] for b in somelists[1] for c in somelists[2]] 

只是添加了一些已经说过的话:如果你使用sympy,你可以使用符号而不是string,这使得它们在math上是有用的。

 import itertools import sympy x, y = sympy.symbols('x y') somelist = [[x,y], [1,2,3], [4,5]] somelist2 = [[1,2], [1,2,3], [4,5]] for element in itertools.product(*somelist): print element 

关于sympy 。

虽然已经有很多答案,但我想分享一下我的想法:

迭代方法

 def cartesian_iterative(pools): result = [[]] for pool in pools: result = [x+[y] for x in result for y in pool] return result 

recursion方法

 def cartesian_recursive(pools): if len(pools) > 2: pools[0] = product(pools[0], pools[1]) del pools[1] return cartesian_recursive(pools) else: pools[0] = product(pools[0], pools[1]) del pools[1] return pools def product(x, y): return [xx + [yy] if isinstance(xx, list) else [xx] + [yy] for xx in x for yy in y] 

Lambda方法

 def cartesian_reduct(pools): return reduce(lambda x,y: product(x,y) , pools) 

上述recursion生成器解决scheme在可变参数中的一个细微修改:

 def product_args(*args): if args: for a in args[0]: for prod in product(*args[1:]) if its[1:] else ((),): yield (a,) + prod 

当然是一个包装,使其工作完全一样的解决scheme:

 def product2(ar_list): """ >>> list(product(())) [()] >>> list(product2(())) [] """ return product_args(*ar_list) 

一个交易 :它检查recursion是否应该在每个外部循环中断,和一个收益 :空的调用没有收益,例如product(()) ,我认为在语义上更正确(参见doctest)。

关于列表理解:math定义适用于任意数量的参数,而列表理解只能处理已知数量的参数。