Как я могу упростить повторяющиеся операторы if-elif в своей функции системы оценок? - PullRequest
20 голосов
/ 04 апреля 2020

Цель состоит в том, чтобы создать программу для преобразования баллов из системы «0 в 1» в систему «F в A»:

  • Если score >= 0.9 выведет «A»
  • Если score >= 0.8 напечатает 'B'
  • 0,7, C
  • 0,6, D
  • И любое значение ниже этой точки, выведите F

Это способ построить его, и он работает в программе, но он несколько повторяется:

if scr >= 0.9:
    print('A')
elif scr >= 0.8:
    print('B')
elif scr >= 0.7:
    print('C')
elif scr >= 0.6:
    print('D')
else:
    print('F')

Я хотел бы знать, есть ли способ построить функцию так что составные утверждения не будут такими же повторяющимися.

Я абсолютный новичок, но будет ли возможно что-то в строках:

def convertgrade(scr, numgrd, ltrgrd):
    if scr >= numgrd:
        return ltrgrd
    if scr < numgrd:
        return ltrgrd

возможно?

Намерение здесь состоит в том, чтобы позже мы могли вызвать его, передавая в качестве аргументов только scr, numbergrade и letter grade:

convertgrade(scr, 0.9, 'A')
convertgrade(scr, 0.8, 'B')
convertgrade(scr, 0.7, 'C')
convertgrade(scr, 0.6, 'D')
convertgrade(scr, 0.6, 'F')

Если было бы возможно передать меньше аргументов, было бы быть еще лучше.

Ответы [ 14 ]

31 голосов
/ 04 апреля 2020

Вы можете использовать модуль bisect для поиска в таблице цифр c:

from bisect import bisect 

def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
     i = bisect(breakpoints, score)
     return grades[i]

>>> [grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]
['F', 'A', 'C', 'C', 'B', 'A', 'A']
10 голосов
/ 04 апреля 2020

Вы можете сделать что-то вроде этих строк:

# if used repeatedly, it's better to declare outside of function and reuse
# grades = list(zip('ABCD', (.9, .8, .7, .6)))

def grade(score):
    grades = zip('ABCD', (.9, .8, .7, .6))
    return next((grade for grade, limit in grades if score >= limit), 'F')

>>> grade(1)
'A'
>>> grade(0.85)
'B'
>>> grade(0.55)
'F'

При этом используется next с параметром по умолчанию для генератора над парами оценок, созданными zip. Это практически точный эквивалент вашего подхода l oop.

5 голосов
/ 04 апреля 2020

В этом конкретном случае c вам не нужны внешние модули или генераторы. Немного основ c математики достаточно (и быстрее)!

grades = ["A", "B", "C", "D", "F"]

def convert_score(score):
    return grades[-max(int(score * 10) - 5, 0) - 1]

# Examples:
print(convert_grade(0.61)) # "D"
print(convert_grade(0.37)) # "F"
print(convert_grade(0.94)) # "A"

5 голосов
/ 04 апреля 2020

Каждому классу можно присвоить пороговое значение:

grades = {"A": 0.9, "B": 0.8, "C": 0.7, "D": 0.6, "E": 0.5}

def convert_grade(scr):
    for ltrgrd, numgrd in grades.items():
        if scr >= numgrd:
            return ltrgrd
    return "F"
2 голосов
/ 18 апреля 2020

У меня есть простая идея, чтобы решить это:

def convert_grade(numgrd):
    number = min(9, int(numgrd * 10))
    number = number if number >= 6 else 4
    return chr(74 - number)

Теперь,

print(convert_grade(.95))  # --> A 
print(convert_grade(.9))  # --> A
print(convert_grade(.4))  # --> F
print(convert_grade(.2))  # --> F
2 голосов
/ 15 апреля 2020

Вы можете использовать np.select из numpy библиотеки для нескольких условий:

>> x = np.array([0.9,0.8,0.7,0.6,0.5])

>> conditions  = [ x >= 0.9,  x >= 0.8, x >= 0.7, x >= 0.6]
>> choices     = ['A','B','C','D']

>> np.select(conditions, choices, default='F')
>> array(['A', 'B', 'C', 'D', 'F'], dtype='<U1')
1 голос
/ 19 апреля 2020
>>> grade = lambda score:'FFFFFFDCBAA'[int(score*100)//10]
>>> grade(0.8)
'B'
1 голос
/ 15 апреля 2020

Вы предоставили простой случай. Однако, если ваша логика c усложняется, вам может понадобиться механизм правил , чтобы справиться с хаосом.

Вы можете попробовать Sauron Rule engine или найти несколько Python правил двигателей от PYPI.

1 голос
/ 15 апреля 2020

Вы можете использовать numpy.searchsorted, что дополнительно дает вам эту замечательную опцию обработки нескольких баллов за один вызов:

import numpy as np

grades = np.array(['F', 'D', 'C', 'B', 'A'])
thresholds = np.arange(0.6, 1, 0.1)

scores = np.array([0.75, 0.83, 0.34, 0.9])
grades[np.searchsorted(thresholds, scores)]  # output: ['C', 'B', 'F', 'A']
0 голосов
/ 25 апреля 2020

Надеюсь, что может помочь следующее: if scr> = 0.9: print ('A') elif 0.9> scr> = 0.8: print ('B') elif 0.8> scr> = 0.7: Print ('C') elif 0.7 scr> = 0.6: печать ('D'), иначе: печать ('F')

...