Benjamin Hodgson
Benjamin Hodgson

Reputation: 44674

Python - switch alternative for non-discrete comparisons

Maybe this question has been asked before, but I couldn't find it. I am trying to implement something that determines what range a given value is in. In this example, x may be any real number.

def f(x):
    if x < 0.1:
        do_something_1()
    elif 0.1 <= x < 1:
        do_something_2()
    elif 1 <= x < 10:
        do_something_3()
    elif x >= 10:
        do_something_4()

...you get the idea.

I've seen plenty of examples of dictionaries replacing switch statements in Python, but I've always understood dictionaries as indexing discrete values.

I find it hard to believe that the if-elif-else chain is the best solution in this situation. Does anyone know of a better one?

Upvotes: 2

Views: 307

Answers (3)

Joel Cornett
Joel Cornett

Reputation: 24788

Here's another way to do it, using a dict and for loop:

ranges_dict = {
    0.1: do_something1,
    1.0: do_something2,
    10.0: do_something3,
    }

for range_val, do_function in sorted(ranges_dict.items()):
    if x < range_val:
        do_function()
        break
else:
    do_something_else()

Upvotes: 1

Sven Marnach
Sven Marnach

Reputation: 602735

An easy way to improve this is not to repeat the lower bounds. Your code is equivalent to

if x < 0.1:
    do_something_1()
elif x < 1:
    do_something_2()
elif x < 10:
    do_something_3()
else:
    do_something_4()

If there are really many values, you might want to bisect instead, but with only four options, the above code is probably the best solutuion, at least in terms of readability and speed.

Upvotes: 12

David Robinson
David Robinson

Reputation: 78660

Use the bisect package to find the index where the value lies, and then call the appropriate function. In your example:

import bisect

def f(x):
    funcs = [do_something_1, do_something_2, do_something_3, do_something_4]
    funcs[bisect.bisect_left([.1, 1, 10], x)]()

Upvotes: 9

Related Questions