lizardowl5151
lizardowl5151

Reputation: 29

shortening many if-elifs? funcitions in dictionary?

As I ended up with many ugly if-elif's when comparing temperature to determine an adjective for the temperature, I thought that I can look for the temperature value in a list in a dictionary, where its key will be the corresponding adjective for the temperature:

def deternmine_temp(temp):

temps = {
    'FREEZING'  : [i for i in range(-20, 0)],
    'very cold' : [i for i in range(0, 6)],
    'cold'      : [i for i in range(6, 11)],
    'chilly'    : [i for i in range(11, 16)],
    'cool'      : [i for i in range(16, 21)],
    'warm'      : [i for i in range(21, 26)],
    'hot'       : [i for i in range(26, 31)],
    'very hot'  : [i for i in range(31, 36)],
    'dangerously hot' : [i for i in range(36, 40)],
    'extremely dangerously hot': [i for i in range(41, 46)]
}

temp = int(temp.replace('°', '').strip())

for word, values in temps.items():
    if temp in values:
        return word

This is a lot better than 7+ if-elif's, but I don't think it is very efficient, especially if temps had a lot more data (for example if I had a narrower range of values that correspond to an adjective).

What would be some ways to make this more efficient? Maybe some functions in the dictionary? Above is really the best I can think of.

Upvotes: 1

Views: 89

Answers (3)

lizardowl5151
lizardowl5151

Reputation: 29

This is closest to what i was looking for.

def switch(x):
    return {
            -20<x<=2: 'FREEZING',
            2<x<=5: 'very cold',
            5<x<=10: 'cold',
            10<x<=15: 'chilly',
            15<x<=22: 'cool',
            22<x<=25: 'warm',
            25<x<=30: 'hot',
            30<x<=33: 'very hot',
            33<x<=35: 'extremely hot',
            35<x<=40: 'dangerously hot'
            }[1]

print(switch(40))

output:

dangerously hot

Upvotes: 0

DYZ
DYZ

Reputation: 57105

If you decide to represent temperature as a floating-point number, your code in general will not work. To make sure your code works with non-integer temperatures (just in case), represent ranges as pairs of min-max values and use explicit comparison:

temps = {
    'FREEZING'  : (-20, 0),
    'very cold' : (0, 6),
    ....
}

for word, values in temps.items():
    if values[0] <= temp < values[1]:
        return word

You may as well use a list of tuples because you do not use dictionary-specific functionality:

temps = [
    ('FREEZING', -20, 0),
    ('very cold', 0, 6),
    ....
]

for word, value1, value2 in temps:
    if value1 <= temp < values2:
        return word

Finally, for consistency, you may define only the upper range boundary (which simultaneously is the lower boundary of the next range):

temps = [
    ('FREEZING', 0),
    ('very cold', 6),
    ....
    ('extremely dangerously hot': float('inf'))
]

for word, value in temps:
    if temp < value:
        return word

Upvotes: 0

Guy
Guy

Reputation: 50909

You need to store the ranges somehow, and since the ranges don't have the same interval you can't really shorten the dictionary initialization. You can extract the dictionary creation to a function, however you will still have to call it as many times as you have options.

You can however remove the list comprehension from the dictionary and replace the loop with next

def deternmine_temp(temp):
    temps = {
            'FREEZING': range(-20, 0),
            'very cold': range(0, 6),
            'cold': range(6, 11),
            'chilly': range(11, 16),
            'cool': range(16, 21),
            'warm': range(21, 26),
            'hot': range(26, 31),
            'very hot': range(31, 36),
            'dangerously hot': range(36, 40),
            'extremely dangerously hot': range(41, 46)
            }

    temp = int(temp.replace('°', '').strip())
    return next((word for word, values in temps.items() if temp in values), None)

Upvotes: 1

Related Questions