如何在评分系统功能中简化重复的if-elif语句?

问题描述 投票:14回答:13

目标是建立一个程序,将分数从“ 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')

如果可以传递更少的参数,那就更好了。

python if-statement dry
13个回答
27
投票

您可以使用bisect模块进行数字表查找:

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

0
投票

您可以使用字典。


0
投票

我有一个简单的主意来解决这个问题:


0
投票
[grade(scr) for scr in [100, 33, 95, 61, 77, 90, 89]]

# ['A', 'F', 'A', 'D', 'C', 'A', 'B']

-3
投票

您可能有一个数字列表,然后是一个等级列表:


10
投票

您可以按照以下方式进行操作:

# 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与默认参数一起使用在next创建的得分等级对上的生成器上。它实际上与循环方法完全等效。


5
投票

您可以为每个等级指定一个阈值:

zip

3
投票

在这种情况下,您不需要外部模块或生成器。一些基本的数学就足够了(并且更快)!

zip

2
投票

您可以在numpy库中使用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" 来满足多种条件:

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"


1
投票

您可以使用np.select,它另外为您提供了一个不错的选择,可以在一个呼叫中处理多个乐谱:

np.select

1
投票

您提供了一个简单的案例。但是,如果您的逻辑变得越来越复杂,则可能需要>> 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') 来处理混乱。

您可以尝试numpy.searchsorted或从PYPI找到一些Python规则引擎。


0
投票

您还可以使用递归方法:

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
投票

这里有一些更简洁,更难以理解的方法:

第一个解决方案需要使用rules engine库中的floor函数。

Sauron Rule engine

并且如果由于某种原因导入grade_mapping = list(zip((0.9, 0.8, 0.7, 0.6, 0), 'ABCDF')) def get_grade(score, index = 0): if score >= grade_mapping[index][0]: return(grade_mapping[index][1]) else: return(get_grade(score, index = index + 1)) >>> print([get_grade(score) for score in [0, 0.59, 0.6, 0.69, 0.79, 0.89, 0.9, 1]]) ['F', 'F', 'D', 'D', 'C', 'B', 'A', 'A'] 库困扰您。您可以对下限功能使用变通方法:

math

这些有点复杂,除非您了解发生了什么,否则我建议您不要使用它们。它们是利用等级增量为0.1的事实的特定解决方案,这意味着使用0.1以外的增量可能无法使用此技术。它还没有用于将标记映射到成绩的简便界面。更通用的解决方案(例如使用bisect的dawg解决方案)可能更合适,或者schwobaseggl的解决方案非常干净。我不太确定为什么要发布此答案,但这只是尝试在没有任何库的情况下解决此问题(我并不是说使用库是不好的),它证明了python的通用性。 >

© www.soinside.com 2019 - 2024. All rights reserved.