Is there a shorter way for if-else networks?

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 an evaluation piece of code that takes the value m, which means sign, and gets an estimate of g. Is there a shorter, not necessarily more pufonic way for the same purpose?

Thanks in advance.

+4
source share
8 answers

First, you can simplify by removing one of the borders:

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 can capture the repetitive nature of the process with a loop (with a default case, representing an option for the 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'
+7
source

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

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

as one insert (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"
+4
source

Pythonic? :

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

, , . .

- :

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)

, ( ).

+4

numpy , searchsorted. : :

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']
+2

, , , .

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

, , . LISP . Haskell .

+1

, :

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]

m, g.

0

Do not change your code. It is readable and easy to maintain.

In general, skip the “smart” one-liners because compilers / interpreters can easily understand your code, but it can be difficult for people to understand it.

0
source

Usage 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 especially applicable if you have more than one class:

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']
0
source

Source: https://habr.com/ru/post/1689294/


All Articles