Terrornado
Terrornado

Reputation: 843

Is there a shorter way for if-else chains?

if (80 <= m <= 100):
    g = "A"
elif (70 <= m < 80):
    g = "B"
elif (60 <= m < 70):
    g = "C"
elif (50 <= m < 60):
    g = "D"
elif (m < 50):
    g = "U"

This is basically a grade measuring piece of code that takes in value m, meaning mark, and obtains grade g. Is there a shorter not necessarily more pythonic way for the same purpose?

Thanks in advance.

Upvotes: 4

Views: 255

Answers (9)

Subham
Subham

Reputation: 411

Using Dict,

m = int(input("Enter Marks:"))

a = {'A' : 80 <= m <= 100, 'B' : 70 <= m < 80, 'C' : 60 <= m < 70, 'D' : 50 <= m < 60, 'U' : m<50}

for key, value in a.items():
    if value == True:
        print(key)

gives

Enter Marks:35
U

[Program finished]

If you want to run this on multiple entries I would suggest switching to a function that returns the letter grade for what ever value you're passing in.

Upvotes: 0

Brad Solomon
Brad Solomon

Reputation: 40878

Using pandas.cut:

import numpy as np
import pandas as pd

bins = [-np.inf, 50, 60, 70, 80, 100]
labels=list('UDCBA')
print(pd.cut(pd.Series(m), bins=bins, labels=labels).iat[0])
# D

This is particularly applicable if you have more than one grade:

grades = np.random.randint(low=45, high=99, size=5)  # 5 grades

print(pd.cut(pd.Series(grades), bins=bins, labels=labels).tolist())
# ['U', 'C', 'A', 'A', 'A']

Upvotes: 0

Engineer
Engineer

Reputation: 48793

Don't change your code. It's readable and easy maintainable.

In general, skip "smart" one-liners, because compilers/interpreters can understand your code easily, but humans can have hard times to understand it.

Upvotes: 0

Paul Panzer
Paul Panzer

Reputation: 53029

If numpy is acceptable there is searchsorted. Free bonus: it can handle an entire list of marks in one go:

import numpy as np

bnds = np.arange(50, 90, 10)
grades = np.array(list('UDCBA'))

marks = [52, 16, 50, 80, 69, 99]

result = grades[np.searchsorted(bnds, marks, side='right')]

print(result)

# ['D' 'U' 'D' 'A' 'C' 'A']

Upvotes: 2

Yann Vernier
Yann Vernier

Reputation: 15877

I'll exploit the single answer and touching ranges to reduce the number of comparisons, but also express the lookup table's structure using a tuple unpacking.

if m <= 100:
    g = next(grade for grade, belowscore in
           (('U',50), ('D',60), ('C',70), ('B',80), ('A',100+1))
           if m < belowscore)

This uses a generator expression to process a list of similar tests, shortcutting by reading only one result. This is inspired by LISP's conditional operation. Haskell has a similar thing in pattern guards.

Upvotes: 1

user2390182
user2390182

Reputation: 73450

Firstly, you can simplify by removing one of the bounds:

if m >= 80:
    g = "A"
elif m >= 70:
    g = "B"
elif m >= 60:
    g = "C"
elif m >= 50:
    g = "D"
else:  # default catch-all
    g = "U"

Secondly, you could capture the repetitive nature of the process by a loop (with the default case presenting an option for a for-else construct):

# iterator: ('A', 80) -> ('B', 70) -> ...
for grade, score in zip('ABCD', (80, 70, 60, 50)):
    if m >= score:
        g = grade
        break
else:  # executed if for-loop isn't 'break'-ed out of
    g = 'U'

Upvotes: 7

Blender
Blender

Reputation: 298046

Shorter and less Pythonic? Definitely:

g='UUUUUDCBAAA'[int(m)//10]

Practically, I think your code conveys its intent well and is easy to read. Most other solutions will not be.

You could also do something like this:

GRADES = {
    'A': (80, float('+inf')),
    'B': (70,  80),
    'C': (60,  70),
    'D': (50,  60),
    'U': ( 0,  50),
}

def letter_grade(points):
    return next(g for g, (start, end) in GRADES.items() if start <= points < end)

I think it is straightforward and can be read the first time through (although I might be biased).

Upvotes: 4

VBB
VBB

Reputation: 1325

Here's another variant, apart from the many already posted:

marks = [0, 50, 60, 70, 80, 100]
grades = ["U", "D", "C", "B", "A"]
g = [grades[i] for i in range(len(grades)) if ((m >= marks[i]) and (m < marks[i+1])) ][0]

The current student's marks are in m and the grade is put in g.

Upvotes: 0

Reblochon Masque
Reblochon Masque

Reputation: 36652

Yes, you could do it this way, but it doesn't reduce the code much:

if m < 50:
    g = "U"
elif m < 60:
    g = "D"
elif m < 70:
    g = "C"
elif m < 80:
    g = "B"
else:
    g = 'A'

as a one liner (which is hard to read):

g = 'U' if m < 50 else "D" if m < 60 else "C" if m < 70 else "B" if m < 80 else "A"

Upvotes: 4

Related Questions