MarkoF
MarkoF

Reputation: 65

How to pass to a function a dictionary whose values are lists

I have a list of parameters such as this:

import numpy as np

param1 = np.arange(0., 1., 0.01)
param2 = np.arange(10., 8000., 100.)
...

I also have a function foo defined with a list of keyword arguments arg1, arg2, ... and their default values:

def foo(arg1=default1, arg2=default2, ...)

What I need to do is call this function, changing one of those default values (one by one) with the arguments and values from my list of parameters like so:

foo(arg1=param1[0])
foo(arg1=param1[1])
...
foo(arg2=param2[0])
foo(arg2=param2[0])

The best way that I thought of was to create a dictionary of all parameters, and then iterate over keys and values and create a new temporary dictionary out of it and then call the function:

all_params = {'arg1':param1, 'arg2':param2, ...}
for key, value_list in all_params.items():
    for value in value_list:
        tmp_dict = {key:value}
        foo(**tmp_dict)

But I have a feeling that 1) I'm iterating in a non-Pythonic way, 2) and that there is obviously a much better way to solve this problem.

EDIT: streamlined the nested loops a bit according to @Sebastian's suggestion.

Upvotes: 1

Views: 88

Answers (3)

Alexander
Alexander

Reputation: 109666

This is relatively simple in my opinion.

def foo(a=0, b=0, c=0):
    return a * b + c

args1 = [1, 2]
args2 = [3, 4, 5]
args3 = [6, 7]

args = [args1, args2, args3]

d = {}
for n, a in enumerate(args):  # Enumerate through all of the parameters.
    for val in a:  # For each parameter, iterate through all of the desired arguments.
        a = [0, 0, 0]  # default_args
        a[n] = val  # Insert the relavent argument into the correct parameter location.
        d[tuple(a)] = foo(*a)  # Call the function and unpack all of the arguments.

# This dictionary holds the function arguments as keys the returned values for those arguments.
>>> d
{(0, 0, 6): 6,
 (0, 0, 7): 7,
 (0, 3, 0): 0,
 (0, 4, 0): 0,
 (0, 5, 0): 0,
 (1, 0, 0): 0,
 (2, 0, 0): 0}

Upvotes: 1

cs95
cs95

Reputation: 402872

1) I'm iterating in a non-Pythonic way

"Pythonic" is subjective.

2) That there is obviously a much better way to solve this problem.

Not so, what you're currently doing is the only possible scenario considering you've to pass them by keyword and that you've to pass them one at a time.


As an improvement you might consider passing all your arguments at the same time.

MVCE:

First, define your function and dictionary:

In [687]: def foo(a, b, c):
     ...:     print(a, b, c)
     ...:  

In [688]: dict_ = {'a': [1, 2, 3], 'b' : [4, 5, 6], 'c' : [7, 8, 9]}

Convert to dict of iters:

In [689]: dict_ = {k : iter(v) for k, v in dict_.items()}

Run your loop:

In [690]: while True:
     ...:     try: 
     ...:         foo(**{k : next(v) for k, v in dict_.items()})
     ...:     except StopIteration: 
     ...:         break
     ...:     
1 4 7
2 5 8
3 6 9

Upvotes: 0

Sebastian
Sebastian

Reputation: 1889

You can simplify the iterating slightly, so that you don't need to access all_params[key] again, like this:

for key, param in all_params.items():
    for value in param:

Upvotes: 0

Related Questions