Reputation: 843
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
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
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
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
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
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
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
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
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
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