9

I wrote some code with a lot of 'if..elif' statements in Python. I know the code style may be considered bad and I want to improve it.

num = int(input('please input a number: '))

if num <= 0:
    print('1')
elif 0 < num <= 5:
    print('2')
elif 5 < num <= 10:
    print('3')
elif 10 < num <= 15:
    print('4')
elif 15 < num <= 20:
    print('5')
elif 20 < num <= 25:
    print('6')

I would like to know how to replace so many 'if..elif' statements with other solutions?

Alex Riley
  • 169,130
  • 45
  • 262
  • 238
zonzely
  • 395
  • 3
  • 6
  • 17
  • 1
    @Huey I disagree. The asker made no indication that any case is executed more often than any other case. – Sam Estep Jun 28 '15 at 02:17
  • Well, [how to replace much 'if…else' in python](http://stackoverflow.com/questions/31095461/how-to-replace-much-if-else-in-python) was flagged as a duplicate. – Huey Jun 28 '15 at 02:21
  • If you were dealing with equality tests (x==1, x==2) then a dictionary of functions can be used. Doesnt apply here, but it is an elegant alternative to big elifs under certain condtions. – JL Peyret Jun 28 '15 at 02:24
  • I have to say I would use http://stackoverflow.com/questions/17166074/most-efficient-way-of-making-an-if-elif-elif-else-statement-when-the-else-is-don solution, so I would also mark this as duplicate. – paulochf Jun 28 '15 at 02:55

6 Answers6

10

You could do something like this:

print(((num - 1) // 5) + 2)

Example when num is 20:

((num - 1) // 5) + 2
((20 - 1) // 5) + 2
(19 // 5) + 2
3 + 2
5

In the general case... not sure. If you're talking about a completely arbitrary if-elif-else construct, then I would say no, at least not in a way that would help readability. In fact, the answer I just gave you for your specific example might not even help readability, so I'm not sure how well you can hope for that in the general case.

Sam Estep
  • 12,974
  • 2
  • 37
  • 75
4

The bisect library could also be used in this situation and would also be quite efficient. The documentation gives a usage example for exam grade boundaries.

This is a really good flexible approach if non linear boundaries are required.

import bisect

def boundaries(num, breakpoints=[0, 5, 10, 15, 20, 25], result='1234567'):
    i = bisect.bisect(breakpoints, num-1)
    return result[i]

num = int(input('Please input a number: '))
print(boundaries(num))
Martin Evans
  • 45,791
  • 17
  • 81
  • 97
3

For simple examples like this where the different cases fit a clear pattern, the best thing would be something like what RedRoboHood suggested where you remove the conditional altogether (modified slightly to support lower bound), e.g.

print('%s' % max((num - 1) // 5 + 2, 1))

If you want to be slightly more general and allow print statements that do not follow a pattern with the input, you could use a python dictionary:

# what to print if num is less than the number but greater than the previous
mapping = {0:'1', 5:'2', 10:'3', 15:'4', 20:'5', 25:'6'}
# clamp the number to the upper bound of the desired range
clamped_num = 5 * max((num - 1) // 5, -1) + 5
print(mapping[clamped_num] if clamped_num in mapping else 'Bad value')

However, there will always be times where you cannot boil it down like this, and for those I think if-else statements are fine.

lemonhead
  • 5,328
  • 1
  • 13
  • 25
3
num = int(input('please input a number: '))

if num < 26:
    print(1 + len([i for i in [0, 5, 10, 15, 20, 25] if i < num]))
Sergey Nosov
  • 350
  • 3
  • 10
2

You could shorten the code a little by removing one of the two < checks on each conditional, like so

num=int(input('please input a number: '))

if num<=0:
    print('1')
elif num<=5:
    print('2')
elif num<=10:
    print('3')
James
  • 1,198
  • 8
  • 14
  • 1
    This is a valid point, though I believe the main issue here is the `if else` structure itself. – Huey Jun 28 '15 at 02:22
1

This is an other way to do it:

a = { '1': (range(1,6)), '2': (range(6,11)), '3': (range(11,16)), '4':(range(16,21)), '5':(range(21,26))}
num=int(input('please input a number: '))
b = {k:v for k,v in a.items() if num in v}
c = b.keys()
print c[0]

in Python3 print(c[0])

Joe T. Boka
  • 6,554
  • 6
  • 29
  • 48