1

Suppose I have an array of functions, each with the same arguments, but each manipulating the arguments in a different way. I then want to iterate over a loop, using my array of functions over and over again to get updated values. How do I pass arguments to the functions?

def f_1(a, b, c):
    val = a + b + c
    return val

def f_2(a, b, c):
    val = a*b + c
    return val

# something like this?

fun_arr = [f_1, f_2]

val1 = [fun_arr[0](a1, b1, c1), fun_arr[1](a1, b1, c1)]
val2 = [fun_arr[0](a2, b2, c2), fun_arr[1](a2, b2, c2)]

I hope the psuedo code above makes sense. It's a simplified version of what I'm trying to do.

If the context helps, I'm trying to write an RK2 algorithm for a system of equations that could possibly be reused for a general set of ODEs. I think I could easily enough write some simple code that applies to my specific problem but I wanted to challenge myself to make my code reusable.

rocksNwaves
  • 5,331
  • 4
  • 38
  • 77
  • 2
    https://docs.python.org/3.7/tutorial/controlflow.html#unpacking-argument-lists – Random Davis May 16 '19 at 19:46
  • @RandomDavis thanks for the link. I just looked over it and I'm going to try to implement it. The examples provided in the below answers will be helpful to. I wish I knew how to hunt down answers in the documentation that quickly... Did you know off the top of your head where that was? If not, what was the search string that helped you find it? – rocksNwaves May 16 '19 at 19:55
  • I knew about argument expansion already so I just had to find that page, but I knew it existed. I learned about it originally because I saw it being used and looked it up. Probably a book would be a good way to learn about all those little things. – Random Davis May 16 '19 at 20:43
  • It is in general easier to design the interface the other way around, using vector valued functions of vector arguments, using vector operations in the integration method. – Lutz Lehmann May 17 '19 at 11:58
  • @LutzL I'm running into a lot of roadblocks on this current approach, even with the good help here. It seems very hard to write a generic RK method for a generic size system. I may give up and write something to solve the small system at hand. – rocksNwaves May 17 '19 at 12:00
  • 1
    You might find some inspiration [here (RK of different orders and step sizes compared)](https://math.stackexchange.com/a/1239002/115115) or [here (using only list and list comprehension to implement RK4, no numpy arrays)](https://stackoverflow.com/a/53922195/3088138) – Lutz Lehmann May 17 '19 at 12:05
  • @LutzL Your code is incredibly concise and easy to understand. The use of the zip function really simplifies everything so much. I don't know how I'll be able to make my code unique after seeing what you did in the second link. Thanks for chiming in just as I was about to give up. – rocksNwaves May 17 '19 at 12:17
  • You can still make the code shorter and more universal by making the lists the primary objects instead of constructing and deconstructing them in every code line. – Lutz Lehmann May 17 '19 at 12:41
  • @LutzL I was just able to successfully make a generic version of your code that accepts a vector field of an arbitrary size! I had to change your tuples to lists (I got an ValueError "generator is already being executed" with the tuples). I also had to use the *args techniques in the answers here, which made me really happy. I know that thanks are frowned on, but i believe credit should be given where it is due! Your help was invaluable! – rocksNwaves May 17 '19 at 18:12

2 Answers2

3

Like this:

fun_arr = [f_1, f_2]

args_list = [
    (a1, b1, c1),
    (a2, b2, c2),
]

val1 = [f(*args_list[0]) for f in fun_arr]

all_vals = [
    [f(*args) for f in fun_arr]
    for args in args_list
    ]
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
1
def solver(fun_arr,*vals):
    new_vals = []
    for v in vals:
        for f in fun_arr:
            new_vals.append(f(v))
Bugbeeb
  • 2,021
  • 1
  • 9
  • 26