【问题标题】:nested for loops to list comprehension with differents "if" conditions嵌套 for 循环以列出具有不同“if”条件的理解
【发布时间】:2019-01-07 14:57:19
【问题描述】:

我正在尝试将此嵌套循环转换为列表理解,但我不确定这是否可行,因为“tmp”列表中的项目可能有不同的值。这是最好的方法吗?谢谢!

final = []
for a in range(-13, 1):
    for b in range(0,4):
        for c in range(6, 49):
            for d in range(48, 94):
                tmp = [0 for i in range(100)]
                for i in range(100):
                    if raw_x[i] >= b and raw_y[i] >= d:
                        tmp [i] = -1
                    if raw_x[i] <= a and raw_y[i] <= c:
                        tmp [i] = 1
                final.append(tmp)

【问题讨论】:

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


    【解决方案1】:

    嵌套推导不是很易读

    一个简单的

    [something for something in container if something > 9]
    

    很棒,但嵌套的经常让人困惑

    您可以简单地将循环移动到生成器函数中 - 它仍然是可读的并允许延迟迭代

    def no_idea_what_this_represents():
        for a in range(-13, 1):
            for b in range(0,4):
                for c in range(6, 49):
                    for d in range(48, 94):
                        tmp = [0 for i in range(100)]
                        for i in range(100):
                            if raw_x[i] >= b and raw_y[i] >= d:
                                tmp [i] = -1
                            if raw_x[i] <= a and raw_y[i] <= c:
                                tmp [i] = 1
                        yield tmp
    
    final = [signs for signs in no_idea_what_this_represents()]
    

    编辑:只是一个自以为是的附录 - 这样可以命名复杂的嵌套循环(出于显而易见的原因,我将其命名为 no_idea_what_this_represents)但是当程序员看到时

    possible_views = [matrix for matrix in camera_matrices()]
    

    他马上就知道这意味着什么

    possible_views = [device.matrix 
                      for devices in itertools.chain(connected_devices(), buffered_devices()
                      for device in devices
                      if device.type=='camera']
    

    让程序员读了很多行,不明显是怎么回事

    【讨论】:

    • 虽然它没有回答实际问题(事实证明 OP 确实只是想了解复杂的理解表达式),但对前提的挑战提出了一个 非常 的好点可读性。 -1 和 +1。
    【解决方案2】:

    这可以在一个表达式中完成,尽管我不确定可读性是否得到改善:

    final = [
        [
            +1 if x <= a and y <= c
            else -1 if x >= b and y >= d
            else 0
            for x, y in zip( raw_x, raw_y )
        ]
        for a in range(-13, 1)
        for b in range(0, 4)
        for c in range(6, 49)
        for d in range(48, 94)
    ]
    

    请注意,我假设您想要遍历 raw_xraw_y整个,而不是每次都恰好 100 个元素:这个问题意味着每次 100 个,但如果意图真的是遍历整个序列,那么最好不要在那里硬编码 100。如果我的意图有误,您可以将内部理解 for 循环更改为 for i in range(100) 并在条件表达式中使用 raw_x[i]raw_y[i] 而不是 xy

    【讨论】:

    • 谢谢,这就是我想知道的,即使可读性没有提高
    【解决方案3】:

    您的算法具有很大的时间复杂度。首先看看这是否实际上是你所需要的。一旦您确定需要一个具有 4 个嵌套级别的嵌套 for 循环,您就可以定义一个函数以在您的列表理解中使用

    在这种情况下,通知内置map 可以接受多个可迭代参数。 functools.partial 允许您使用预设参数定义函数。

    from functools import partial
    
    def get_val(x, y, a, b, c, d):
        if x <= a and y <= c:
            return 1
        if x >= b and y >= d:
            return -1
        return 0
    
    final = [list(map(partial(get_val, a=a, b=b, c=c, d=d), raw_x, raw_y)) \
             for a in range(-13, 1) \
             for b in range(0, 4) \
             for c in range(6, 49) \
             for d in range(48, 94)]
    

    【讨论】:

    • @tobias_k map 将列表 raw_xraw_y 解包为元素 xy
    • @jez 啊,对,没有看到(显然没有阅读说明)。
    • 请注意,如果要匹配问题,严格来说,-1 和 +1 的优先顺序应该交换。在问题中,如果x &lt;=a and y&lt;=c 然后值 +1 会覆盖之前的值,即使它之前设置为 -1
    • @jez,感谢您的指出。是的,这是真的,因为 OP 可能会覆盖每个 if 语句中的值(有意或无意,尚不清楚)。现已更正。
    • @TmSmth 在这种情况下请注意,我的回答也复制了问题的 +1 -over- -1 优先级
    猜你喜欢
    • 2022-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-06
    • 1970-01-01
    相关资源
    最近更新 更多