查找列表的笛卡尔积,根据条件过滤掉元素

时间:2018-02-14 16:21:10

标签: python

我最近遇到了这种符号

a = [1,2,3,4]
b = [2,4,6]

c = [(x,y,z) for x in a for y in b for z in a]

首先,我不知道如何在创建c时搜索符号,这种类型的结构是否有名称?

此外,我确信c可以更新为不允许x等于z。请你能帮帮我吗?

我尝试了各种各样的事情

c = [(x,y,z) for x in a for y in b for z in a for x != z]

但到目前为止,我无法找到有效的内容,甚至是有效的语法。

我想要完成的是找到(a,b,a)的每个组合,其中a只能在每一行中使用一次,因此结果将是

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

由于

4 个答案:

答案 0 :(得分:3)

它被称为 list comprehension ,您可以在其中使用逻辑if 来过滤返回列表中的结果:

>>> a = [1,2,3,4]
>>> b = [2,4,6]
#     if condition to skip results where `x` equals `z` v
>>> c = [(x,y,z) for x in a for y in b for z in a if x != z]
>>> c   
[(1, 2, 2), (1, 2, 3), (1, 2, 4), (1, 4, 2), (1, 4, 3), (1, 4, 4), (1, 6, 2), (1, 6, 3), (1, 6, 4), (2, 2, 1), (2, 2, 3), (2, 2, 4), (2, 4, 1), (2, 4, 3), (2, 4, 4), (2, 6, 1), (2, 6, 3), (2, 6, 4), (3, 2, 1), (3, 2, 2), (3, 2, 4), (3, 4, 1), (3, 4, 2), (3, 4, 4), (3, 6, 1), (3, 6, 2), (3, 6, 4), (4, 2, 1), (4, 2, 2), (4, 2, 3), (4, 4, 1), (4, 4, 2), (4, 4, 3), (4, 6, 1), (4, 6, 2), (4, 6, 3)]

您可以使用itertools.product获得相同的行为,而不是使用嵌套列表理解

>>> from itertools import product

>>> [(x,y,z) for x, y, z in product(a, b, a) if x !=z]
[(1, 2, 2), (1, 2, 3), (1, 2, 4), (1, 4, 2), (1, 4, 3), (1, 4, 4), (1, 6, 2), (1, 6, 3), (1, 6, 4), (2, 2, 1), (2, 2, 3), (2, 2, 4), (2, 4, 1), (2, 4, 3), (2, 4, 4), (2, 6, 1), (2, 6, 3), (2, 6, 4), (3, 2, 1), (3, 2, 2), (3, 2, 4), (3, 4, 1), (3, 4, 2), (3, 4, 4), (3, 6, 1), (3, 6, 2), (3, 6, 4), (4, 2, 1), (4, 2, 2), (4, 2, 3), (4, 4, 1), (4, 4, 2), (4, 4, 3), (4, 6, 1), (4, 6, 2), (4, 6, 3)]

答案 1 :(得分:1)

这是list comprehension,过滤条件的正确语法是:

c = [(x,y,z) for x in a for y in b for z in a if x != z]

List comprehensions

答案 2 :(得分:1)

用于创建c的语法称为list comprehension。几乎你的确切情况是这些文档中的第四个代码示例:

  

列表推导由括号组成,括号中包含一个表达式,后跟一个for子句,然后是零个或多个for或if子句。结果将是一个新列表,该列表是通过在其后面的for和if子句的上下文中计算表达式得到的。例如,如果列表不相等,则此listcomp将两个列表的元素组合在一起:

     
    

>>> [(x,y)对于[1,2,3]中的x,对于[3,1,4]中的y,如果x!= y]

         

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

  

您需要做的就是将上次for更改为if

c = [(x,y,z) for x in a for y in b for z in a if x != z]

答案 3 :(得分:0)

为了多样化,我想添加以下基于itertools.product规避 if检查的解决方案。

from itertools import product
a = [1,2,3,4]
b = [2,4,6]

c = []
for i, item in enumerate(a):
    c.extend((item, x, y) for x, y in product(b, a[:i] + a[i+1:]))
print(c)
制造

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

我也做了一些时间来比较使用的不同方法:

from timeit import timeit

setup = '''

from itertools import product


def list_comp(a, b):
    return [(x,y,z) for x in a for y in b for z in a if x != z]


def itertools_listComp(a, b):
    return [(x,y,z) for x, y, z in product(a, b, a) if x !=z]


def itertools_forLoop(a, b):
    c = []
    for i, item in enumerate(a):
        c.extend((item, x, y) for x, y in product(b, a[:i] + a[i + 1:]))
    return c

a = [1, 2, 3, 4]
b = [2, 4, 6]
'''

print('list_comp:', timeit(stmt="list_comp(a, b)", setup=setup, number=1000))
print('itertools_forLoop:', timeit(stmt="itertools_forLoop(a, b)", setup=setup, number=1000))
print('itertools_listComp:', timeit(stmt="itertools_listComp(a, b)", setup=setup, number=1000))

结果是:

list_comp:          0.0050
itertools_listComp: 0.0056
itertools_forLoop:  0.0086

所以似乎普通列表理解是最快的。此行为也会因较大的a列表而持续存在。