简体   繁体   English

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

[英]Find cartesian product of lists filtering out the elements based on condition

I recently came across this notation 我最近遇到了这种表示法

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]

First I don't know how to search for the notation in creating c , is there a name for this type of structure? 首先,我不知道如何在创建c搜索表示法,这种结构是否有名称?

Also, I'm confident that c can be updated to not allow x to equal z . 另外,我有信心可以将c更新为不允许x等于z Please can you help me with this? 请你能帮我吗?

I've tried various things on the lines of 我已经尝试过各种方法

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

but so far I can't find anything that works, or is even valid syntax. 但是到目前为止,我找不到任何有效的语法。

What I'm trying to accomplish is to find every combination of (a,b,a) where a can only be used once in each line so the result would be 我要完成的工作是找到(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)]

Thanks 谢谢

It is known as list comprehension and you can use logical if within it to filter the results in the returned list as: 它被称为列表理解 ,你可以使用逻辑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)]

Instead of using nested list comprehension , you may get the same behavior using itertools.product as well: 除了使用嵌套列表 itertools.product ,您还可以使用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)]

this is list comprehension and the correct syntax for the filtering condition is this: 这是list comprehension并且过滤条件的正确语法是:

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

List comprehensions 清单理解

The syntax being used to create c is called a list comprehension . 用于创建c的语法称为列表理解 Almost your exact case is the fourth code example in those docs: 几乎您的确切情况是这些文档中的第四个代码示例:

A list comprehension consists of brackets containing an expression followed by a for clause, then zero or more for or if clauses. 列表推导由包含表达式的方括号组成,后跟一个for子句,然后是零个或多个for或if子句。 The result will be a new list resulting from evaluating the expression in the context of the for and if clauses which follow it. 结果将是一个新列表,该列表是通过在其后的for和if子句的上下文中评估表达式而得出的。 For example, this listcomp combines the elements of two lists if they are not equal: 例如,如果两个列表的元素不相等,则此listcomp组合它们:

>>>[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y] >>> [[(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)] [(1、3),(1、4),(2、3),(2、1),(2、4),(3、1),(3、4)]

All you need to do is change your last for to an if : 您需要做的就是将最后一个更改for if

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

Just for the sake of variety, I would like to add the following solution that is based on itertools.product and circumvents the if check. 仅出于多样性的考虑,我想添加以下基于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)

producing: 生产:

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

I did some timings too to compare the different approaches using: 我也做了一些时间比较使用以下不同的方法:

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

and the results are: 结果是:

list_comp:          0.0050
itertools_listComp: 0.0056
itertools_forLoop:  0.0086

So it seems that the plain list comprehension is the fastest. 因此,似乎简单的列表理解是最快的。 This behavior persists with bigger a lists too. 这种现象在更大a列表中也仍然存在。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM