如何在if,elif条件下转换具有多个语句的for循环到List Comprehensions

问题描述 投票:-1回答:1
for i in range(len(q)):
        # q.remove(max(q))
        # maxi = max(q)

    if((q.index(max(q)))+3) in range(len(q)):
            return("Too chaotic")

    if((q.index(max(q)))+2) in range(len(q)):
            bribe = bribe + 2
            q.remove(max(q))
    elif ((q.index(max(q)))+1) in range(len(q)):
            bribe = bribe + 1
            q.remove(max(q))
    elif(q.index(max(q))) == (len(q)-1):
            q.remove(max(q))
 return(bribe)

我想将上面的for循环转换为list comprehension。我试过了

["Too chaotic" if((q.index(max(q)))+3) in range(len(q)) 
 bribe+2,q.remove(max(q)) if((q.index(max(q)))+2) in range(len(q))  
 else [bribe+2,q.remove(max(q)]  if((q.index(max(q)))+2) in range(len(q)) 
 else q.remove(max(q)) if (q.inde  (max(q))) == (len(q)-1) for i in 
 range(len(q))]

但它不起作用。

python-3.x list-comprehension
1个回答
0
投票

SO上有几十个这样的问题:如何将这段代码转换成列表/字典理解?我看到了三个主要目标:

  • 性能:一个想要提高速度或减少代码的内存占用;
  • 表现力:一个人想要一个简洁明了的代码;
  • 学习/娱乐/实验:一个人想要了解列表理解自己。

但有时候,我们根本就不知道。这就是这种情况,因此我将从通用思想开始。

按照重要性顺序,在创建列表推导之前,这是我的经验法则:

  1. 从一个干净的代码开始,因为列表理解不会使你的代码更清晰(实际上它可能恰恰相反)
  2. 确保要创建列表的列表或聚合函数(总和,最大值,...)
  3. 确保代码的控制流不使用跳转(returnbreakraise,...)
  4. 确保您不会产生任何副作用。

让我们尝试使用这些规则来解决您的问题。

Clean the code

要修复的第一件事是返回值的类型。根据具体情况,您可以返回字符串或整数。虽然Python没有强制函数来输入一致性,但你应该避免这种混淆。您可以返回特殊值(-1)或引发异常。

以下是一些需要解决的问题:

你得到:

for _ in range(len(q)):
    m = max(q)
    max_q_index = q.index(m) # position of the max
    if max_q_index < len(q) - 3:
        return -1

    if max_q_index < len(q) - 2:
        bribe = bribe + 2
        q.remove(m)
    elif max_q_index < len(q) - 1:
        bribe = bribe + 1
        q.remove(m)
    elif max_q_index == len(q)-1:
        q.remove(m)
    # no else since max_index < len(q)

它更好,但可以改进。你实际上有四种不同的情况:

  • max_q_index == len(q)-1
  • max_q_index == len(q)-2
  • max_q_index == len(q)-3
  • max_q_index < len(q)-3

你应该更换<来表达这一点。在前三种情况下,从q中删除max:

for _ in range(len(q)):
    m = max(q)
    max_q_index = q.index(max(q)) # position of the max
    if max_index < len(q) - 3:
        return -1

    if max_index == len(q) - 3:
        bribe = bribe + 2
    elif max_index == len(q) - 2:
        bribe = bribe + 1
    q.remove(m)

现在我们了解发生了什么:如果列表几乎已经排序,则max总是在最后三个项目中,循环遍历q的每个元素。否则,你打破了。你可以这样写:

for _ in range(len(q)):
    m = max(q)
    max_q_index = q.index(m) # position of the max
    distance = len(q) - 1 - max_q_index
    if distance >= 3:
        return -1

    bribe += distance
    q.remove(m)

Should I use a list comprehension?

你需要一个距离之和,因此观察规则2,但控制流使用跳跃:一旦找到distance >= 3就返回,并且在每次迭代时从q中移除元素(副作用)。你不应该在这里使用列表理解。

Bonus

您可以使用不同的策略:对值及其索引进行排序:

>>> L = [1,2,4,3,7,5]
>>> list(zip(L, range(len(L))))
[(1, 0), (2, 1), (4, 2), (3, 3), (7, 4), (5, 5)]
>>> S = sorted(zip(L, range(len(L))))
>>> S
[(1, 0), (2, 1), (3, 3), (4, 2), (5, 5), (7, 4)]

函数zip压缩列表的元素和数字0,1,2,3,4 ......,即它们在列表中的位置。我们按值对生成的元组进行排序。现在,将元组(位置)的第二个值与元组的当前索引进行比较:如果位置低于或等于索引,则max不是列表的最后一个元素,我们会增加贿赂;如果位置大于索引,则max是列表的最高值。

>>> bribe = 0
>>> for i, (_, pos) in enumerate(S):
...     distance = max(i - pos, 0)
...     if distance >= 3:
...         raise Exception() # can't return outside of a function.
...     bribe += distance
...
>>> bribe
2

有了L = [1,2,7,3,4,5],你会得到一个例外。

如果您不需要distance >= 3的快捷方式,则可以使用列表推导:

>>> L = [1,2,4,3,7,5]
>>> sum(max(i - pos, 0) for i, (_, pos) in enumerate(sorted(zip(L, range(len(L))))))
2
>>> L = [1,2,7,3,4,5]
>>> sum(max(i - pos, 0) for i, (_, pos) in enumerate(sorted(zip(L, range(len(L))))))
3

有可能破解列表理解以抛出异常并满足初始行为,但不要这样做。

© www.soinside.com 2019 - 2024. All rights reserved.