Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 得到一系列列表的笛卡尔积?_Python_List_Cartesian Product - Fatal编程技术网

Python 得到一系列列表的笛卡尔积?

Python 得到一系列列表的笛卡尔积?,python,list,cartesian-product,Python,List,Cartesian Product,如何从一组列表中获得笛卡尔积(每个可能的值组合) 输入: 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) ...] 可从Python2.6获得 import itertools somelists = [ [1, 2, 3], ['a', 'b'],

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

输入:

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) ...]
可从Python2.6获得

import itertools

somelists = [
   [1, 2, 3],
   ['a', 'b'],
   [4, 5]
]
for element in itertools.product(*somelists):
    print(element)
这和,

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


在Python2.6及更高版本中,可以使用“itertools.product”。在较旧版本的Python中,您可以使用以下(几乎——请参阅文档)等效项,至少作为起点:

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)

两者的结果都是一个迭代器,因此如果您确实需要一个列表进行进一步的处理,请对Python 2.5及更早版本使用
list(result)

>>> [(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)]
下面是
product()
的递归版本(只是一个示例):

例如:

>>> 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())
[()]

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

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)]

对已经说过的话再补充一点:如果你使用sympy,你可以使用符号而不是字符串,这使得它们在数学上很有用

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

关于。

我会使用列表理解:

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]]

对上述可变风格的递归生成器解决方案进行了细微修改:

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
当然还有一个包装器,它的工作原理与该解决方案完全相同:

def product2(ar_list):
    """
    >>> list(product(()))
    [()]
    >>> list(product2(()))
    []
    """
    return product_args(*ar_list)
使用一个权衡:它检查递归是否应该在每个外部循环上中断,一个增益:空调用时不产生收益,例如
产品(())
,我认为这在语义上更正确(请参阅doctest)


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

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

迭代法 递归方法 Lambda法
递归方法:

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)
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)
def giveAllLists(a, t):
    if (t + 1 == len(a)):
        x = []
        for i in a[t]:
            p = [i]
            x.append(p)
        return x
    x = []

    out = giveAllLists(a, t + 1)
    for i in a[t]:

        for j in range(len(out)):
            p = [i]
            for oz in out[j]:
                p.append(oz)
            x.append(p)
    return x

xx= [[1,2,3],[22,34,'se'],['k']]
print(giveAllLists(xx, 0))


迭代方法:

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)
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)
def giveAllLists(a, t):
    if (t + 1 == len(a)):
        x = []
        for i in a[t]:
            p = [i]
            x.append(p)
        return x
    x = []

    out = giveAllLists(a, t + 1)
    for i in a[t]:

        for j in range(len(out)):
            p = [i]
            for oz in out[j]:
                p.append(oz)
            x.append(p)
    return x

xx= [[1,2,3],[22,34,'se'],['k']]
print(giveAllLists(xx, 0))



巨石阵方法:

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)
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)
def giveAllLists(a, t):
    if (t + 1 == len(a)):
        x = []
        for i in a[t]:
            p = [i]
            x.append(p)
        return x
    x = []

    out = giveAllLists(a, t + 1)
    for i in a[t]:

        for j in range(len(out)):
            p = [i]
            for oz in out[j]:
                p.append(oz)
            x.append(p)
    return x

xx= [[1,2,3],[22,34,'se'],['k']]
print(giveAllLists(xx, 0))


输出:

[[1, 22, 'k'], [1, 34, 'k'], [1, 'se', 'k'], [2, 22, 'k'], [2, 34, 'k'], [2, 'se', 'k'], [3, 22, 'k'], [3, 34, 'k'], [3, 'se', 'k']]
我相信这是可行的:

def cartesian_product(L):  
   if L:
       return {(a,) + b for a in L[0] 
                        for b in cartesian_product(L[1:])}
   else:
       return {()}

您可以使用标准库中的
itertools.product
获取笛卡尔积。
itertools
中的其他酷的相关实用程序包括
置换
组合
,以及带有替换的
组合。下面是针对以下代码段的python代码笔:

来自itertools导入产品的

某些列表=[
[1, 2, 3],
['a','b'],
[4, 5]
]
结果=列表(产品(*SomeList))
打印(结果)
提前拒绝: 我必须得到一个非常大的笛卡尔乘积的第一个结果。尽管我只想要一件东西,但要花很长时间。问题是,由于结果的顺序,在找到正确的结果之前,它必须遍历许多不需要的结果。因此,如果我有10个50个元素的列表,并且前两个列表中的第一个元素不兼容,那么它必须遍历最后8个列表的笛卡尔积,尽管它们都会被拒绝



此实现允许在结果包含每个列表中的一项之前对其进行测试。因此,当我检查某个元素是否与先前列表中已包含的元素不兼容时,我会立即转到当前列表的下一个元素,而不是遍历以下列表中的所有产品。

根据文档,实际的itertools.product实现不会生成中间结果,这可能很贵。对于中等规模的列表,使用此技术可能会很快失控。我只能将OP指向文档,而不是为他阅读。文档中的代码旨在演示产品功能的功能,不是Python早期版本的变通方法。请注意,“每种可能的组合”与“笛卡尔乘积”并不完全相同,因为笛卡尔乘积中允许重复。笛卡尔乘积是否有非重复版本?@KJW是,
set(笛卡尔乘积)
笛卡尔乘积中不应存在重复项,除非输入列表本身包含重复项。如果您希望笛卡尔乘积中没有重复项,请在所有输入列表中使用
set(inputlist)
。从数学上讲,笛卡尔积是一个集合,所以笛卡尔积不包含重复项。另一方面,如果输入有重复项,
itertools.product
将在输出中有重复项。因此,严格来说,
itertools.product
不是笛卡尔积,除非将输入包装在
set
中,如@CamilB所述。如果一些
参数
是迭代器,则递归版本不起作用。如果使用OP提供的变量SomeList,则需要添加“*”字符。SomeList之前的
*
有什么用?它的作用是什么?@VineetKumarDoshi:这里它用于将列表解压为函数调用的多个参数。请在此处阅读更多信息:注意:仅当每个列表至少包含一个item@igo当任何列表包含零项时,它也能工作——至少一个零大小列表和任何其他列表的笛卡尔乘积是空列表,这正是它产生的结果。它们存储在堆栈中,尽管如此。@QuentinPradet你是说像
def():while True:yield 1
这样的生成器在我们处理它的过程中会不断增加其堆栈大小吗?@QuentinPradet是的,但即使在这种情况下,也只需要最大深度所需的堆栈,而不是整个列表,所以在这种情况下,堆栈为3是真的,对不起。基准可能很有趣。:)SomeList之前的
*
有什么用?@VineetKumarDoshi“product(SomeList)”是子列表之间的笛卡尔乘积,Python首先将“[1,2,3]”作为元素,然后在下一个逗号之后获取另一个元素,这就是换行符,因此第一个乘积项是([1,2,3]),类似于第二个([4,5]),等等”[([1,2,3],),([4,5],),([6,7],)]”。如果您想在元组内的元素之间获得笛卡尔乘积,您需要告诉带星号的Python
def my_product(pools: List[List[Any]], rules: Dict[Any, List[Any]], forbidden: List[Any]) -> Iterator[Tuple[Any]]:
    """
    Compute the cartesian product except it rejects some combinations based on provided rules
    
    :param pools: the values to calculate the Cartesian product on 
    :param rules: a dict specifying which values each value is incompatible with
    :param forbidden: values that are never authorized in the combinations
    :return: the cartesian product
    """
    if not pools:
        return

    included = set()

    # if an element has an entry of 0, it's acceptable, if greater than 0, it's rejected, cannot be negative
    incompatibles = defaultdict(int)
    for value in forbidden:
        incompatibles[value] += 1
    selections = [-1] * len(pools)
    pool_idx = 0

    def current_value():
        return pools[pool_idx][selections[pool_idx]]

    while True:
        # Discard incompatibilities from value from previous iteration on same pool
        if selections[pool_idx] >= 0:
            for value in rules[current_value()]:
                incompatibles[value] -= 1
            included.discard(current_value())

        # Try to get to next value of same pool
        if selections[pool_idx] != len(pools[pool_idx]) - 1:
            selections[pool_idx] += 1
        # Get to previous pool if current is exhausted
        elif pool_idx != 0:
            selections[pool_idx] = - 1
            pool_idx -= 1
            continue
        # Done if first pool is exhausted
        else:
            break

        # Add incompatibilities of newly added value
        for value in rules[current_value()]:
            incompatibles[value] += 1
        included.add(current_value())

        # Skip value if incompatible
        if incompatibles[current_value()] or \
                any(intersection in included for intersection in rules[current_value()]):
            continue

        # Submit combination if we're at last pool
        if pools[pool_idx] == pools[-1]:
            yield tuple(pool[selection] for pool, selection in zip(pools, selections))
        # Else get to next pool
        else:
            pool_idx += 1