-2

Im trying to return the 'students' grades according to what they got on python. I used a bunch of elif statements but i dont feel like this is efficient. I was wondering if there are any other ways i can present this as? possibly smaller. Ive attempted using for loops and dictionaries, but im not getting it, maybe cuz i dont understand dictionaries well loll

def grade_select(grade):
    if grade <  40: return "D-"
    elif grade <= 40 and grade < 45: return "D"
    elif grade <= 45 and grade < 50: return "D+"
    elif grade <= 50 and grade < 55: return "C-"
    elif grade <= 55 and grade < 60: return "C"
    elif grade <= 60 and grade < 65: return "C+"
    elif grade <= 65 and grade < 70: return "B-"
    elif grade <= 70 and grade < 75: return "B"
    elif grade <= 75 and grade < 80: return "B+"
    elif grade <= 80 and grade < 85: return "A-"
    elif grade <= 85 and grade < 90: return "A" 
    elif grade >= 90: return "A+"

5 Answers5

3

since you return when a condition is matched, you do not need to use elif just if.

moreover, the previous condition eliminates the need of checking if the value is "between".

def grade_select(grade):
    if grade < 40: return "D-"
    if grade < 45: return "D"
    if grade < 50: return "D+"
    if grade < 55: return "C-"
    if grade < 60: return "C"
    if grade < 65: return "C+"
    if grade < 70: return "B-"
    if grade < 75: return "B"
    if grade < 80: return "B+"
    if grade < 85: return "A-"
    if grade < 90: return "A" 
    return "A+"

an alternative would be to declare a dictionary and calculate where the grade fits.

grades = { 40: "D-", 45: "D", 50: "D+", 55: "C-", 60: "C", 65: "C+", 70: "B-", 75: "B", 80: "B+", 85: "A-", 90: "A", 100: "A+" }

def grade_select(grade):
    grade = (grade // 5 * 5) + 5

    if grade < 40:
        grade = 40
    elif grade > 90:
        grade = 100

    return grades[grade]
Paulo Pereira
  • 1,064
  • 8
  • 16
1

You can use a dictionary to store the range and it's according grade value:

def grade_select(grade):
    dct = {
        range(0, 40): "D-",
        range(40, 45): "D",
        range(45, 50): "D+",
        ...
        range(90, 100 + 1): "A+"
    }
    dct = {g: m for r, m in dct.items() for g in r}
    return dct[grade]
Matiiss
  • 5,970
  • 2
  • 12
  • 29
1

Well, your condition is kinda weird, because

elif grade <= 40 and grade < 50

has no sense (if grade <= 40 then grade < 50 of course)

But I think you wanna write something like this:

if 40 <= grade < 50:
    pass

You can use syntax above, it could make it a little bit better. Also, you can check this article

Vladyslav
  • 97
  • 7
0

Here's the fastest version that calculates an index based on the grade value. This method only works if your grade ranges are all five wide.

_lettergrades = ['D-', 'D', 'D+', 'C-', 'C', 'C+', 'B-', 'B', 'B+', 'A-', 'A', 'A+']

def grade_select(grade):  
    return _lettergrades[(max(min(grade, 90), 35) - 35) // 5]

If your ranges weren't consistently five wide you could use bisect.bisect_right to get an index for the letter grade. The search uses bisection, which should be faster than a linear search. (The lists _thresholds and _lettergrades are global to avoid recreating them for every call to grade_select().)

from bisect import bisect_right
    
_thresholds = [40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90]
_lettergrades = ['D-', 'D', 'D+', 'C-', 'C', 'C+', 'B-', 'B', 'B+', 'A-', 'A', 'A+']

def grade_select(grade):
    return _lettergrades[bisect_right(_thresholds, grade)]

Note: I doubt speed matters as much as clarity here. For clarity I like Paulo Pereira's answer best.

Steven Rumbalski
  • 44,786
  • 9
  • 89
  • 119
-1

I guess using dictionary is the best way

def grade_select(grade):
    d = {
        'D-':range(0,40),
        'D':range(45,50),
        'D+':range(50,55),
        'C-':range(55,60) #, etc.
    }

    return [k for k,v in d.items() if grade in v][0]
Dmitriy Neledva
  • 867
  • 4
  • 10
  • Returning a list is wrong. You could use a plain for-loop instead: `for k,v in d.items(): if grade in v: return k` – wjandrea Sep 19 '22 at 23:02
  • @wjandrea you're right, I was inattentive. but I guess list comprehention is still better (and faster) than for loop, we just need to add `[0]` to get rid of list. `return [k for k,v in d.items() if grade in v][0]` – Dmitriy Neledva Sep 20 '22 at 05:30
  • Better how? It's harder to read and it can't return early. The plain for-loop is in fact better. – wjandrea Sep 20 '22 at 16:56
  • 1
    I'm wrong for loop would be better for this situation – Dmitriy Neledva Sep 20 '22 at 19:35