user2242044
user2242044

Reputation: 9233

Most efficient way to recode these multiple if statements

I know this is a ridiculous example, but I'm looking for a more efficient way to write this code. Each project gets different values added to it depending on what state it takes place in. This is just a small snippet. I could potentially want to extend this out for all 50 states, which would be a lot of if statements. I could dump this in a function, but then the function would still have all the if statements.

Projects = [['Project A', 'CT', '', ''], ['Project B', 'MA', '', ''], ['Project C', 'RI', '', '']]

for project in Projects:
    if project[1] == 'CT':
        project[2] = project[0] + project[1]
        project[3] = '222'
    elif project[1] == 'MA':
        project[2] = '123'
        project[3] = None
    elif project[1] == 'ME':
        project[2] = '12323'
        project[3] = '333'
    elif project[1] == 'RI':
        project[2] = 'asdf'
        project[3] = '3333'
print Projects

Upvotes: 2

Views: 246

Answers (2)

jonrsharpe
jonrsharpe

Reputation: 122086

To expand on my comment and mescalinum's answer, if some of the impacts on project[2] will be derived from other values in the project, you can put callable objects (e.g. by using lambda expressions) in the dictionary:

IMPACTS = {
    'CT': (lambda project: project[0] + project[1], '222'),
    'MA': ('123', None),
    ...,
}

Then you can apply it like:

for project in Projects:
    two, three = IMPACTS[project[1]]
    try:
        project[2] = two(project)
    except TypeError:
        project[2] = two 
    project[3] = three

If some of project[3]'s values will vary, you can similarly make them callable in the dictionary and apply the same try/except logic (or if callable(...)) to filter those that need calling.

Upvotes: 2

fferri
fferri

Reputation: 18950

Using a dictionary mapping:

for project in Projects:
    project[2:4] = {
        'CT': [project[0]+project[1], '222'],
        'MA': ['123', None],
        'ME': ['12323', '333'],
        'RI': ['asdf', '3333']
    }[project[1]]

removes all the if/else, and just deals with real data :)

As suggested by jonrsharpe, it may be more efficient delaying the evaluation of the dictionary values with lambdas (at the cost of writing more):

for project in Projects:
    project[2:4] = {
        'CT': lambda: [project[0]+project[1], '222'],
        'MA': lambda: ['123', None],
        'ME': lambda: ['12323', '333'],
        'RI': lambda: ['asdf', '3333']
    }[project[1]]()


Edit: explanation for user2242044:

consider the function:

def foo(x):
    print('*** foo(%s)' % x)
    return x

and see what happens when you do:

>>> {1: foo(1), 2: foo(2)}[1]
*** foo(1)
*** foo(2)
1

as you see, it computes all the values in dictionary, calling both foo(1) and foo(2), for then just using the value of foo(1).

With lambdas:

>>> {1: lambda: foo(1), 2: lambda: foo(2)}[1]()
*** foo(1)
1

the dictionary returns a function, and when you call the function, the value is computed, thus computing only the value of foo(1)

Upvotes: 8

Related Questions