olirwin
olirwin

Reputation: 605

Avoiding nested conditions

I am designing a program in which I'm trying to avoid nesting conditional statements.

Basically, I have 2 sets of 3 parameters : a_changes, b_changes and c_changes are bools, and they are associated with a, b and c, that are lists if they change or floats if they don't. My aim is to transform non-changing parameters into lists of the same length as changing parameters.

An example would be :

a_changes = True
b_changes = False
c_changes = False
a = [0.21, 0.25, 0.29]
b = 0.13
c = 0.78

becomes

a_changes = True
b_changes = False
c_changes = False
a = [0.21, 0.25, 0.29]
b = [0.13, 0.13, 0.13]
c = [0.78, 0.78, 0.78]

Problem is : multiple parameters can change at the same time, so you could have :

a_changes = True
b_changes = True
c_changes = False
a = [0.21, 0.25, 0.29]
b = [0.13, 0.13, 0.13]
c = 0.78

becomes

a_changes = True
b_changes = True
c_changes = False
a = [0.21, 0.25, 0.29]
b = [0.13, 0.13, 0.13]
c = [0.78, 0.78, 0.78]

If multiple parameters change, their length is the same, so no problem coming from there. However, I would want to avoid having a multitude of nested conditional statements. Is it at all possible? Is there a Data Structure I could use?

Upvotes: 1

Views: 108

Answers (3)

Mad Physicist
Mad Physicist

Reputation: 114330

You have a lot of redundant information it seems. The processing really only depends on whether something is a list: booleans are not necessary. Also, you don't need separate variables, since it's easier to work with batches of things when they are in a sequence.

Store your data in a list:

data = [a, b, c]

Get the length of a list:

size = next((len(x) for x in data if isinstance(x, list)), 1)

Notice that this call to next guards against all the elements being float by returning one. Now do the transform:

for i in range(len(data)):
    if ~isinstance(data[i], list):
        data[i] = [data[i]] * size

Or more concisely:

data = [x if isinstance(x, list) else [x] * size for x in data]

Upvotes: 1

Patrick Artner
Patrick Artner

Reputation: 51653

This should work if at least one input is a list:

def refine_arguments(a, b, c, a_changes, b_changes, c_changes):

    # get the max len of one of the list (should be all the same listlenght)      
    maxlen = max(len(i) for i in (a, b, c) if isinstance(i, list))

    # if the X_changes is true use the float value times maxlen, else leave as is
    a = [a] * maxlen if not a_changes and not isinstance(a, list) else a
    b = [b] * maxlen if not b_changes and not isinstance(b, list) else b
    c = [c] * maxlen if not c_changes and not isinstance(c, list) else c

    return a, b, c


a_changes = True
b_changes = True
c_changes = False
a = [0.21, 0.25, 0.29]
b = [0.13, 0.13, 0.13]
c = 0.78

print(*refine_arguments(a, b, c, a_changes, b_changes, c_changes))

a_changes = True
b_changes = False
c_changes = False
a = [0.21, 0.25, 0.29]
b = 0.78
c = 0.78

print(*refine_arguments(a, b, c, a_changes, b_changes, c_changes))

Output:

[0.21, 0.25, 0.29] [0.13, 0.13, 0.13] [0.78, 0.78, 0.78]
[0.21, 0.25, 0.29] [0.78, 0.78, 0.78] [0.78, 0.78, 0.78]

Use a,b,c = refine_arguments(a, b, c, a_changes, b_changes, c_changes) to work with a,b,c later on.

Upvotes: 1

dnalow
dnalow

Reputation: 984

The data structure you may want to use are numpy arrays. If you have a lot of parameters, use a dictionary to allow loop operations:

my_data = {}

my_data["a"] = [0.21, 0.25, 0.29]
my_data["b"] = 0.13
my_data["c"] = 0.78

length = 1

for param in my_data:
    my_data[param] = np.array(my_data[param], ndmin=1) # at least 1d
    length = max(length, len(my_data[param]))

for param in my_data:
    my_data[param] = np.ones(length) * my_data[param] # make sure all is the same lentgh


Upvotes: 1

Related Questions