Demetri Pananos
Demetri Pananos

Reputation: 7404

How can I apply a function to itself?

Suppose I have function, f, which takes in some variable and returns a variable of the same type. For simplicity, let's say

def f(x):
    return x/2+1

I'm interested in applying f to itself over and over. Something like f(f(f(...(f(x))...))).

I could do this like

s = f(x)
for i in range(100):
    s = f(s)

But I was wondering if there was a simpler, less verbose way to doing the same thing. I wan't to avoid for loops (just as a challenge to myself). Is there maybe some way of using map or a similar function to accomplish this?

Upvotes: 9

Views: 1064

Answers (7)

You could factor out recursion:

from functools import partial
recurse = partial(lambda g,f,x,n: g(g,f,x,n), # capture g
                  lambda g,f,x,n: n and g(g, f, f(x), n-1) or x)

If you're into something better than a one-liner, recursion can be abolished:

import itertools
def recurse(f, x, n):
  for _ in itertools.repeat(None, n):
    x = f(x)
  return x

Then:

>>> f = lambda x: x/2+1
>>> recurse(f, 42, 5)
7.0
>>> f(f(f(42)))
7.0

Upvotes: 0

John Kugelman
John Kugelman

Reputation: 361967

Is there maybe some way of using map or a similar function to accomplish this?

Not map, but reduce. I wouldn't use it for this, but you could call reduce on an n-item sequence to cause f to be called n times. For example:

>>> def f(x):
...   return x+1
... 
>>> reduce(lambda n,_: f(n), range(100), 42)
142

Explanation:

  • n is assigned each successive return value of f.
  • _ is the list of numbers from range(100). These numbers are all ignored. All that matters is how many there are.
  • 42 is the starting value.

100 nested calls to f(f(f...(f(42))...)) results in 142.

Upvotes: 8

Josh Lee
Josh Lee

Reputation: 177715

In Python, a for loop is the most ergonomic and readable way to do this. So I would consider this mostly an exercise — these are more natural to use in functional languages.

functools.reduce collapses a list of values to a single value by repeatedly calling a function of two arguments. Here's factorial:

>>> import functools, operator
>>> operator.mul(2,3)
6
>>> functools.reduce(operator.mul, range(1, 10), 1)
362880

We can abuse this to use a list of values for its length only and ignore the actual contents.

>>> def f(x):
...   return x/2+1
... 
>>> functools.reduce(lambda x, y: f(x), range(10), 1)
1.9990234375

Or we can string together n copies of the (unary) function in a list and collapse them by applying each one to the accumulated value.

>>> import itertools
>>> functools.reduce(lambda x, g: g(x), itertools.repeat(f, 10), 1)
1.9990234375

Upvotes: 5

ernest_k
ernest_k

Reputation: 45339

The construct would be recursion. But recursion requires that your call stack ends at some point. Such a case could work with an algorithm such as:

if(x == 0):
    return 1
# this will make sure it ends at the preceding line in the next call
return f(x - 1) 

This is typically the approach used to compute results such as the factorial.

To use an example, adding a requirement (that you only compute if x < 2, just as an example):

def f(x):
  if(x < 2):
    return 1
  return f(x/2+1)

The key is that there be a point at which the call stack starts returning (to avoid an overflow)

Upvotes: 1

Ajax1234
Ajax1234

Reputation: 71461

While it is not clear from your example if you are trying to calculate a final numerical result or accumulate a list of values, you can use a very simple recursive approach with a lambda function:

Single value:

f = lambda x, c = 1:x if c == 100 else f(x/2 + 1, c+1)
>>f(200)
2

List of values:

f = lambda x, c = 1:x if c == 100 else f(x+[x[-1]/2+1], c+1)
>>f([200])
[200, 101, 51, 26, 14, 8, 5, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

Upvotes: 2

pmanderson54
pmanderson54

Reputation: 46

What I think you're asking about is concept called Recursion. You could use something like a lambda function but recursive calls in a for loop aren't inherently bad. I'd go read more about recursive functions in general and then look for python implementations specifically.

Upvotes: -1

Novice
Novice

Reputation: 915

You could add the function itself in the return line of the definition. An example would be the top answer here How can I build a recursive function in python?

Upvotes: 0

Related Questions