所以我是Python的新手,有一个概念需要适应一下,那就是列表理解。我读到过,正确使用它们可以提高计算速度,如果你要用正确的方法学习Python,它们是需要好好了解的。
我正在写一个程序,实现一个粒子聚集算法,涉及到10^6个粒子积累到一个成长的簇。我正在回溯我的代码,尽可能地优化任何地方的性能,我有以下函数。
def step_all_walkers(walkers):
updated_positions = []
for walker in walkers:
decision = random.randint(1,4)
if decision == 1:
updated_walker = (min(walker[0]+1, N-1), walker[1])
elif decision == 2:
updated_walker = (max(walker[0]-1, 1), walker[1])
elif decision == 3:
updated_walker = (walker[0], min(walker[1] + 1, N-1))
elif decision == 4:
updated_walker = (walker[0], max(walker[1]-1, 1))
updated_positions.append(updated_walker)
return updated_positions
这个函数让每一个粒子(或步行者,我在代码中称他们为 "步行者")向随机方向迈出单位长度的一步,并防止粒子从N×N的网格中走出来。我注意到,我正在创建并返回一个新的列表。updated_positions
,而且由于这个列表和输入的 walker
列表可能非常大,我对列表理解的了解告诉我,这可能是使用列表理解的好时机。然而,在其他一些关于这个问题的帖子中,当只有一个ifelse需要被评估时,人们回答说只要使用一个好的时尚的for循环就可以了。
那么我有几个问题。
1)多个ifelif语句可以在列表理解中完成吗?
2)把这个for循环写成list comprehension有意义吗?这样做有什么好处吗?
我问这个问题的主要目的是为了建立更多的直觉,知道什么时候适合用list comprehension,同时也想看看是否可以用list comprehension让这个函数更有效率。
我会把它变成一个查找字典开始,然后你可能会考虑一个列表理解法
decisions = {1: lambda walker: (min(walker[0]+1, N-1), walker[1])}
return [decisions[random.randint(1,4)](walker) for walker in walkers]
一个案例,其中 列表理解法 是当逻辑太复杂的时候。
For循环就比较简单了,因为它允许。
然而,正如Sayse所建议的那样,我们通常可以通过额外的数据结构和帮助函数来简化逻辑,从而实现列表理解。
不使用ifelse语句的列表理解法 (需要逻辑旁路)
def step_all_walkers(walkers, N):
def decision(walker):
" Helper function for making a decisions "
# Place decision choices into a data structure
options = [
lambda walker: (min(walker[0]+1, N-1), walker[1]),
lambda walker: (max(walker[0]-1, 1), walker[1]),
lambda walker: (walker[0], min(walker[1] + 1, N-1)),
lambda walker: (walker[0], max(walker[1]-1, 1))]
while True:
n = random.randint(0, 3) # use rather than (1, 4) to
# provide proper index into options
yield options[n](walker)
# Now, list comprehension is straight forward to follow
return [decision(walker) for walker in walkers]