【问题标题】:how to rewrite this loop in a more efficient way in python如何在python中以更有效的方式重写这个循环
【发布时间】:2009-09-23 14:18:23
【问题描述】:

我有以下类型的循环:

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.. 中的元素。对不起,伙计们。然而,我之前的问题的解决方案对我也遇到的其他问题非常有帮助。谢谢。

【问题讨论】:

    标签: python list list-comprehension


    【解决方案1】:

    考虑一下

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

    【讨论】:

    • 把它变成一个列表理解会更快吗?
    • 您的解决方案很有帮助,我非常感谢。但是我错过了原始问题中的一些内容..你能再看一遍吗?非常感谢!
    • 在我的循环中,b 的新元素引用了 b 本身(通过 b[-1])。为此,我认为您的解决方案不正确。
    【解决方案2】:

    对于您最初提出的将函数映射到输入序列对的问题,以下将起作用,并且与停留在 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。

    【讨论】:

      【解决方案3】:

      总会有一些循环或其他循环,但可能会减少开销的一种可能性是:

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

        试试这样的:

        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 而不是 list 理解

        【讨论】:

          猜你喜欢
          • 2021-11-18
          • 2023-03-26
          • 1970-01-01
          • 2022-11-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-04-14
          相关资源
          最近更新 更多