4

Given a list of functions (functions) and an integer n, I'm trying to figure out a way to compose them stepwise, and return a list of each stepwise result as follows:

compose_step([lambda x: x+3, lambda x: x+5, lambda x: x+1], 8) --> [8, 11, 16, 17]

So, as of now I have figured out how to compose a list of functions and return the result as follows:

def compose(functions, n):
    def compose2(f,g):
        return lambda x: f(g(x))
    composedFunction = functools.reduce(compose2, functions, lambda x: x)
    return composedFunction(n)

However, I'm extremely confused how to keep track of each step and return it as a list. I'm assuming that I need to use map somehow in order to map each stepwise piece to the list. I have also come up with a method to apply all functions in the list to n as such:

def apply_all_functions(functions, n):
    answerList = list(map(methodcaller('__call__', n), functions)))
    return answerList

I was thinking of somehow using the composeFunction function to compose a new list of stepwise functions, all the way up until the fully composed function, and then using this as my new list for the apply_all_functions in order to achieve the desired result. But currently, I'm pretty stumped.

1
  • Can you explain more what is your aim here? I don't understand what is your input and expected output. Commented Apr 24, 2018 at 22:30

3 Answers 3

4

You can use itertools.accumulate with a composition function

from itertools import accumulate

def compose(f, g):
    return lambda x: f(g(x))

funcs = [lambda x: x, lambda x: x+3, lambda x: x+5, lambda x: x+1]

print([f(8) for f in accumulate(funcs, compose)])
# [8, 11, 16, 17]
Sign up to request clarification or add additional context in comments.

Comments

1

itertools.accumulate is the way to go, but if you're wondering how you could do it on your own, here's one way

def apply_all (x, f = None, *fs):
  if f is None:
    return []
  else:
    next = f (x)
    return [ next ] + apply_all(next, *fs)

funcs = \
  [ lambda x: x
  , lambda x: x+3
  , lambda x: x+5
  , lambda x: x+1
  ]

print(apply_all(8, *funcs))
# [ 8, 11, 16, 17 ]

If you need the form in your original question

def apply_all (fs, x):
  if not fs:
    return []
  else:
    next = fs[0](x)
    return [ next ] + apply_all(fs[1:], next)

funcs = \
  [ lambda x: x
  , lambda x: x+3
  , lambda x: x+5
  , lambda x: x+1
  ]

print(apply_all(funcs, 8))
# [ 8, 11, 16, 17 ]

The above form operates on fs[0] and fs[1:] which shows this can be expressed as a vanilla reduce

from functools import reduce

def apply_all (fs, x):
  def reducer (acc, f):
    (seq, x) = acc
    next = f (x)
    return (seq + [next], next)
  return reduce(reducer, fs, ([], x)) [0]

funcs = \
  [ lambda x: x
  , lambda x: x+3
  , lambda x: x+5
  , lambda x: x+1
  ]

print(apply_all(funcs, 8))
# [ 8, 11, 16, 17 ]

Comments

0

You can also use itertools.accumulate with an initial value:

from itertools import accumulate


def compose(data, funcs):
    yield from accumulate(funcs, lambda data, f: f(data), initial=data)


funcs = [lambda x: x+3, lambda x: x+5, lambda x: x+1]
init = 8
print(list(compose(init, funcs)))
# [8, 11, 16, 17]

You can do something similar with functools.reduce if you don't want the intermediate results.

This is similar to @Patrick's answer, but here accumulate applies each function and yields the stepwise result one by one instead of generating composed functions.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.