【问题标题】:python - Single Line Nested For Loopspython - 单行嵌套 For 循环
【发布时间】:2018-09-15 20:57:37
【问题描述】:

以下代码的python单行等效项是什么?

l=[]
for i in range(3,5) :
    if i==3:
        for j in range(0,2):
            if i%2:
                l.append(i*j)
            else:
                l.append(i+j)
    else:
        l.append(i)
print(l)

我尝试使用单行进行嵌套循环,但只有一个条件如下:

print([i*j if i%2 else i+j for i in range(3,5) for j in range(0,2)])

注意:这里我想学习如何在两个循环中使用 if else 条件的嵌套循环使用单行等效项。 另外,如果不可能,请说明原因!

提前致谢:)

【问题讨论】:

  • 大多数代码不应该达到这种复杂性。如果确实如此,最好像您那样编写它以保留功能和可读性。列表推导式(这是它们的实际名称)更适合更简单的循环和条件。
  • 我们中的一些人来自做这种事情自然的语言。我其实很喜欢这个问题。 Python 确实让嵌套变得比想象的更困难。
  • 我同意,这很有趣,但我肯定必须打开我的解释器并开始尝试让语法完美。
  • 三层嵌套是非常传统的,但是python没有把它作为优先级(求助于理解可能只会使代码更加模糊)

标签: python python-3.x list list-comprehension


【解决方案1】:

您可以将您的内部部分转换为一系列列表:

[[i * j if i % 2 else i + j for j in range(2)] if i == 3 else [i] for i in range(3,5)]

在一般情况下展开 2D 可迭代对象很容易:

[e for row in iterable for e in row]

两者结合:

[e for row in [[i * j if i % 2 else i + j for j in range(2)] if i == 3 else [i] for i in range(3,5)] for e in row]

您可以避免使用生成器存储中间列表:

[e for row in ((i * j if i % 2 else i + j for j in range(2)) if i == 3 else [i] for i in range(3,5)) for e in row]

【讨论】:

  • 这太棒了,但它是否规避了人们用其他答案提出的问题? (即:性能比等效的 for 循环差,而且非常难以阅读)(我会说它很难阅读,但看起来不像其他答案那样受诅咒)
  • @bittahProfessional。我不确定性能,但公平地说,这个问题可以改写为“我怎样才能让这段代码变得更糟”。如果你有一个很好的 for 循环,它并不简单地遵循理解模式,那就别管它了。
【解决方案2】:

我想出的是为每个i 生成一个序列,然后有一个封闭的理解将它们展平为一个列表:

[x for y in ((i*j if i%2 else i+j for j in range(0, 2)) if i == 3 else (i,) for i in range(3, 5)) for x in y]
# [0, 3, 4]

显然,这比嵌套版本更复杂、更难阅读,而且性能可能更差。

【讨论】:

    【解决方案3】:

    这是一个可怕的怪物:

    [x for i in range(3,5) for x in ([i*j if i%2 else i+j for j in range(2)] if i==3 else (i,))]
    

    我正在努力使它可读:

    In [12]: result = [
        ...:     x
        ...:     for i in range(3, 5)
        ...:     for x in ((i*j if i%2 else i+j for j in range(2))
        ...:               if i ==3 else (i,))
        ...: ]
    
    In [13]: print(result)
    [0, 3, 4]
    

    正如 cmets 中所指出的,您的循环不应该变得如此复杂。您应该在此处使用函数来使您的代码更具可读性。它还将使列表理解的使用变得不那么笨拙。你的目标不应该是“保持一致”。你的目标应该是“保持我的代码可读、可维护、简单和诚实”。这个列表理解不是那些东西。

    注意,我不认为这会表现得更好。它需要创建额外的匿名容器或生成器\list-comprehensions(这需要在底层创建和调用函数对象)。

    您编写代码的目标不应该是“我如何学习编写越来越复杂的列表推导”,而应该是“我如何编写和组织我的代码,以便使用简单易读的列表推导”。

    【讨论】:

    • 这不是增加了数量吗?循环数,从而增加代码的时间复杂度?是的,我知道可读性应该是第一要务,但我也想学习如何在两个循环中使用带有 if-else 块的列表推导。我的意思是出于好奇想知道 if 语句的放置位置。
    • @Trifrostmaster “这不是增加了循环的数量,从而增加了代码的时间复杂度吗?”不,增加的循环并不意味着增加的复杂性。这是经验法则,而不是逻辑含义。时间复杂度是等价的,(尽管我认为实际运行时会支持 for-loop 版本而不是滥用的 list-comprehension
    • @Trifrostmaster 好吧,从学术的角度来看这很好,但你不应该在生产代码中使用它。这就是我要澄清的全部内容,因为我感到有责任,因为这些问题经常被试图为生产编写代码的人看到。这种事情会让你在适当的代码审查中受到谴责。
    【解决方案4】:

    我会先尝试以下方法:

    [(i*j if i % 2 and i==3
      else i+j if i==3
      else i)
     for j in range(0, 2)
     for i in range(3, 5)]
    

    嵌套列表理解语法会变得非常混乱。这是输出:

    [0, 4, 3, 4]
    

    我想你可以把它做成一个集合来消除欺骗:

    result = list(set(result))
    # where result is the list above 
    
    [0, 3, 4]
    

    【讨论】:

    • 把它变成一个集合然后回到一个列表是可行的,虽然这个方法不是很可靠。
    【解决方案5】:

    这是我想出的: print(list(set([i*j if i % 2 else i+j if i==3 else i for i in range(3, 5) for j in range(0, 2)])))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-05
      • 2019-04-15
      • 2012-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-09
      相关资源
      最近更新 更多