如何在Python中以更高效的方式重写这个循环
我有一个这样的循环:
a = range(10)
b = [something]
for i in range(len(a)-1):
b.append(someFunction(b[-1], a[i], a[i+1]))
不过,这个for循环让性能下降很多。我尝试写一个窗口生成器,每次给我两个元素,但最后还是需要明确的for循环。有没有办法让这个过程更简洁、更高效,符合Python的风格呢?
谢谢
补充:我忘了提到b中的元素……抱歉大家。不过,我之前问题的解决方案对我其他问题也很有帮助。谢谢。
4 个回答
2
总会有某种循环存在,但有一种方法可能会减少开销:
import itertools
def generate(a, item):
a1, a2 = itertools.tee(a)
next(a2)
for x1, x2 in itertools.izip(a1, a2):
item = someFunction(item, x1, x2)
yield item
可以这样使用:
b.extend(generate(a, b[-1]))
4
针对你最开始提到的问题,也就是对输入序列中的每一对进行函数映射,下面的代码可以解决这个问题,而且在Python中效率也算不错。
from itertools import tee
a = range(10)
a1, a2 = tee(a)
a2.next()
b = map(someFunction, a1, a2)
至于扩展的问题,也就是你需要访问上一次迭代的结果,这种内部状态在函数式编程中叫做“展开”。不过,Python并没有提供这种展开的结构,主要是因为在这种情况下,使用for循环会更容易理解,而且通常也会更快。为了让代码更符合Python的风格,我建议把成对迭代的部分提取到一个函数中,并创建一个明确的循环变量。
def pairwise(seq):
a, b = tee(seq)
b.next()
return izip(a, b)
def unfold_over_pairwise(unfolder, seq, initial):
state = initial
for cur_item, next_item in pairwise(seq):
state = unfolder(state, cur_item, next_item)
yield state
b = [something]
b.extend(unfold_over_pairwise(someFunction, a, initial=b[-1]))
如果循环的开销真的成了问题,那说明someFunction这个函数应该非常简单。在这种情况下,最好是用更快的语言,比如C,来写整个循环。
8
考虑一下这个
def make_b( a, seed ):
yield seed
for a,b in zip( a[:-1], a[1:] ):
seed= someFunction( seed, a, b )
yield seed
这让你可以做到这个
a = xrange(10)
b= list(make_b(a,something))
注意,你通常可以使用这个:
b = make_b(a)
而不是实际创建一个 b
列表。将 b
作为生成器函数可以节省大量存储空间(还有一些时间),因为你可能根本不需要一个 list
对象。通常,你只需要一些可以迭代的东西。
对于 a
也是一样。它不一定要是一个 list
,只要是一些可以迭代的东西——比如带有 yield
语句的生成器函数。