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))]
但它不起作用。
SO上有几十个这样的问题:如何将这段代码转换成列表/字典理解?我看到了三个主要目标:
但有时候,我们根本就不知道。这就是这种情况,因此我将从通用思想开始。
按照重要性顺序,在创建列表推导之前,这是我的经验法则:
return
,break
,raise
,...)让我们尝试使用这些规则来解决您的问题。
要修复的第一件事是返回值的类型。根据具体情况,您可以返回字符串或整数。虽然Python没有强制函数来输入一致性,但你应该避免这种混淆。您可以返回特殊值(-1
)或引发异常。
以下是一些需要解决的问题:
i
:用_
取代它(见What is the purpose of the single underscore "_" variable in Python?);q.index(max(q))
一次并将其存储在变量max_q_index
中;x in range(len(q))
的意思是0 <= x < len(q)
;你得到:
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)
你需要一个距离之和,因此观察规则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不是列表的最后一个元素,我们会增加贿赂;如果位置大于索引,则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
有可能破解列表理解以抛出异常并满足初始行为,但不要这样做。