Search code examples
pythoniteratorfunctools

apply function repeatedly in python without loops


I have a python function that I'd like to apply to a value many, many times. I know I can do it with a for loop:

for i in range(N_iter):
    val=f(val)

But is there a more efficient way, maybe using itertools or functools?


Solution

  • There's at least two things you can do: use local variables and unroll the loop.

    Here's the baseline:

    def f(x):
      return x+1
    
    N_iter=16777216
    val=0
    for i in range(N_iter):
        val=f(val)
    print(val)
    

    On my system, this takes about 0m2.448s.

    Here's the code when all references are local, meaning that Python won't have to load and store them each time:

    def f(x):
      return x+1
    
    def iterate(f, N_iter, val):
      for i in range(N_iter):
          val=f(val)
      print(val)
    
    iterate(f, 16777216, 0)
    

    This takes 0m1.648s.

    You can also manually unroll the loop, doing more iterations per jump. Here's 8 (for simplicity it doesn't handle remainders):

    def f(x):
      return x+1
    
    def iterate(f, N_iter, val):
      for i in range(N_iter//8):
          val=f(val)
          val=f(val)
          val=f(val)
          val=f(val)
          val=f(val)
          val=f(val)
          val=f(val)
          val=f(val)
      print(val)
    
    iterate(f, 16777216, 0)
    

    This takes 0m1.327s.

    Together, they've sped up this tight loop up by nearly 50%.

    When you reach this level of microoptimization, it may be worth rethinking the whole approach or rewriting in a faster language.