Get the cartesian product of a series of lists?
如何从一组列表中获得笛卡尔积(每个可能的值组合)?
输入:
1 2 3 4 5 | somelists = [ [1, 2, 3], ['a', 'b'], [4, 5] ] |
期望输出:
1 | [(1, 'a', 4), (1, 'a', 5), (1, 'b', 4), (1, 'b', 5), (2, 'a', 4), (2, 'a', 5) ...] |
在Python 2.6)
1 2 3 | import itertools for element in itertools.product(*somelists): print(element) |
文档:itertools.product Python 3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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及以上:
1 2 3 4 | >>> [(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)] |
这是递归的(只是一
1 2 3 4 5 | def product(*args): if not args: return iter(((),)) # yield tuple() return (items + (item,) for items in product(*args[:-1]) for item in args[-1]) |
例子:
1 2 3 4 5 6 7 8 9 10 | >>> 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:
1 2 | import itertools result = list(itertools.product(*somelists)) |
你可以在Python 2.6或以上的使用itertools.product `。在旧版本的Python,你可以用以下的(几乎相当于代码-见文档)从文档,至少的出发点:
1 2 3 4 5 6 7 8 9 | 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) |
结果是两个迭代器,所以如果你真的需要的话furthert
我会使用列表的理解:
1 2 3 4 5 6 7 | 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]] |
这里是一个递归发电机,这不是任何临时表店
1 2 3 4 5 6 7 8 9 | 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 | [(1, 3, 5), (1, 3, 6), (1, 4, 5), (1, 4, 6), (2, 3, 5), (2, 3, 6), (2, 4, 5), (2, 4, 6)] |
虽然已经有很多的答案,我想分享一些我的想法:
迭代方法
1 2 3 4 5 | def cartesian_iterative(pools): result = [[]] for pool in pools: result = [x+[y] for x in result for y in pool] return result |
递归的方法
1 2 3 4 5 6 7 8 9 10 11 | 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方法
1 2 | def cartesian_reduct(pools): return reduce(lambda x,y: product(x,y) , pools) |
递归的方法:
1 2 3 4 5 6 7 8 9 10 11 12 | def rec_cart(start, array, partial, results): if len(partial) == len(array): results.append(partial) return for element in array[start]: rec_cart(start+1, array, partial+[element], results) rec_res = [] some_lists = [[1, 2, 3], ['a', 'b'], [4, 5]] rec_cart(0, some_lists, [], rec_res) print(rec_res) |
迭代的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def itr_cart(array): results = [[]] for i in range(len(array)): temp = [] for res in results: for element in array[i]: temp.append(res+[element]) results = temp return results some_lists = [[1, 2, 3], ['a', 'b'], [4, 5]] itr_res = itr_cart(some_lists) print(itr_res) |
次要的修改对上述解决方案的递归发生器中味:可变
1 2 3 4 5 | def product_args(*args): if args: for a in args[0]: for prod in product_args(*args[1:]) if args[1:] else ((),): yield (a,) + prod |
当然,这和它的工作,使包装的解决方案是相同的:
1 2 3 4 5 6 7 8 | def product2(ar_list): """ >>> list(product(())) [()] >>> list(product2(())) [] """ return product_args(*ar_list) |
它具有一个权衡:如果要在每个递归检查中断的外环,和一个空的产量增益:在呼叫,e.g.
关于链表的理解:数学定义适用于一个参数列表数,而只处理已知的理解可以从他们的号码。
只是添加到已经是位有sympy说:如果你使用,你可以使用符号的字符串,而不是让他们mathematically有用。
1 2 3 4 5 6 7 8 9 10 | 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。