【问题标题】:Find cartesian product of lists filtering out the elements based on condition查找列表的笛卡尔积,根据条件过滤掉元素
【发布时间】:2018-02-15 00:46:33
【问题描述】:

我最近遇到了这个符号

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

谢谢

【问题讨论】:

  • 你想做什么?你想要的输出是什么? c 正在使用 list comprehension 创建

标签: python


【解决方案1】:

它被称为 list comprehension,您可以在其中使用 logical 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)]

【讨论】:

  • 谢谢,您为我节省了大量的嵌套循环和 if 语句
【解决方案2】:

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

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

List comprehensions

【讨论】:

    【解决方案3】:

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

    列表推导式由包含表达式的括号组成,后跟一个 for 子句,然后是零个或多个 for 或 if 子句。结果将是一个新列表,该列表是在其后面的 for 和 if 子句的上下文中评估表达式而产生的。例如,如果两个列表的元素不相等,则此 listcomp 会合并它们:

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

    【讨论】:

      【解决方案4】:

      为了多样化,我想添加以下基于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 列表中也存在。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多