Search code examples
pythonlist-comprehensionreducefoldfunctools

How to apply a list of functions sequentially to a string using Python reduce or list comprehension?


Problem Statement

I would like to apply a list of functions fs = [ f, g, h ] sequentially to a string text=' abCdEf '

Something like f( g( h( text) ) ).

This could easily be accomplished with the following code:

# initial text
text = '  abCDef   '

# list of functions to apply sequentially
fs = [str.rstrip, str.lstrip, str.lower]

for f in fs:
    text = f(text)

# expected result is 'abcdef' with spaces stripped, and all lowercase
print(text)

Using functools.reduce

It seems that functools.reduce should do the job here, since it "consumes" the list of functions at each iteration.

from functools import reduce

# I know `reduce` requires two arguments, but I don't even know
# which one to chose as text of function from the list
reduce(f(text), fs)

# first interaction should call
y = str.rstrip('   abCDef   ')  --> '    abCDef' 

# next iterations fails, because tries to call '   abCDef'() -- as a function 

Unfortunately, this code doesn't work, since each iteration returns a string istead of a function, and fails with TypeError : 'str' object is not callable.

QUESTION: Is there any solution using map, reduce or list comprehension to this problem?


Solution

  • reduce can take three arguments:

    reduce(function, iterable, initializer)
    

    What are these three arguments in general?

    • function is a function of two arguments. Let's call these two arguments t and f.
    • the first argument, t, will start as initializer; then will continue as the return value of the previous call of function.
    • the second argument, f, is taken from iterable.

    What are these three arguments in our case?

    • the iterable is your list of function;
    • the second argument f is going to be one of the functions;
    • the first argument t must be the text;
    • the initializer must be the initial text;
    • the return of function must be the resulting text;
    • function(t, f) must be f(t).

    Finally:

    from functools import reduce
    
    # initial text
    text = '  abCDef   '
    
    # list of functions to apply sequentially
    fs = [str.rstrip, str.lstrip, str.lower]
    
    result = reduce(lambda t,f: f(t), fs, text)
    
    print(repr(result))
    # 'abcdef'