如何将if,elif条件中的带有多语句的for循环转换为List Comprehensions

时间:2019-04-06 17:38:09

标签: python-3.x list-comprehension

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循环转换为列表理解。我尝试做

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

但是没有用。

1 个答案:

答案 0 :(得分:0)

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

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

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

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

  1. 从干净的代码开始,因为列表理解不会使您的代码更简洁(实际上可能相反)
  2. 确保要创建列表列表的汇总函数(总和,最大值,...)
  3. 确保代码的控制流不使用跳转(returnbreakraise,...)
  4. 请确保您没有任何副作用。

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

清除代码

要解决的第一件事是返回值的类型。根据情况,您可以返回字符串或整数。尽管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中删除了最大值:

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)

现在,我们了解发生了什么:如果列表几乎已排序,则最大值始终位于最后三个项目中,并且循环遍历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)

我应该使用列表理解吗?

您想要一个距离的总和,因此遵守规则2,但是控制流使用跳转:找到distance >= 3后立即返回,并且每次迭代都从q中删除元素(副作用)。 您不应在此处使用列表理解。

奖金

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

>>> 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不是列表的最后一个元素,我们增加了贿赂;如果位置大于索引,则最大值为列表的最大值。

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

可以破解列表理解以引发异常并满足最初的行为,但是不要这样做。