1

我有以下类型的循环:

a = range(10)
b = [something]
for i in range(len(a)-1):
    b.append(someFunction(b[-1], a[i], a[i+1]))

然而,for循环正在扼杀很多性能。我曾尝试编写一个 Windows 生成器,以便每次都给我 2 个元素,但它最终仍然需要显式的 for 循环。有没有办法以 Python 的方式使这个更短、更高效?

谢谢

编辑:我忘记了 b 中的元素。对不起,伙计们。然而,我之前的问题的解决方案对我也遇到的其他问题非常有帮助。谢谢。

4

4 回答 4

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语句的生成器函数。

于 2009-09-23T14:27:06.607 回答
4

对于您最初提出的将函数映射到输入序列对的问题,以下将起作用,并且在停留在 Python 领域时与它所获得的效率差不多。

from itertools import tee

a = range(10)
a1, a2 = tee(a)
a2.next()
b = map(someFunction, a1, a2)

至于需要访问上一次迭代结果的扩展问题——这种内部状态存在于函数概念展开中。但是 Python 不包含展开构造,并且出于充分的理由,循环在这种情况下更具可读性并且很可能也更快。至于让它更 Pythonic,我建议将成对迭代提升到一个函数并创建一个显式循环变量。

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。

于 2009-09-23T14:22:43.660 回答
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]))
于 2009-09-23T15:14:36.147 回答
0

尝试这样的事情:

a = range(10)    
b = [something] 

s = len(b)
b+= [0] * (len(a) - 1)
[ b.__setitem__(i, someFunction(b[i-1], a[i-s], a[i-s+1])) for i in range(s, len(b))]

还:

  • 使用来自 itertools 的函数也应该很有用(早期帖子)
  • 也许你可以重写 someFunction 并使用 map 而不是列表理解
于 2009-09-23T16:58:08.510 回答