등급 시스템 기능에서 반복적 인 if-elif 문을 어떻게 단순화 할 수 있습니까?


20

목표는 점수를 '0 to 1'시스템에서 'F to A'시스템으로 변환하는 프로그램을 구축하는 것입니다.

  • score >= 0.9'A'를 인쇄 하면
  • score >= 0.8'B'를 인쇄 하면
  • 0.7, C
  • 0.6, D
  • 그리고 그 지점보다 낮은 값은

이것은 그것을 빌드하는 방법이며 프로그램에서 작동하지만 다소 반복적입니다.

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

더 적은 수의 인수를 전달할 수 있으면 더 좋습니다.



답변:


30

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

2
사용에 대한 추가 +1을 원합니다 bisect. 이것은 너무 드물게 사용됩니다.
norok2

4
@ norok2 4 가지 요소의 목록이 시작해야 할 곳이라고 생각하지 않습니다. 이러한 작은 목록의 경우 선형 스캔이 더 빠를 수 있습니다. 헤드 업없이 변경 가능한 기본 인수 사용;)
schwobaseggl

1
물론, 그것은 문제의 학습 측면을 해치지 않고 아프지 않지만 나는 그것이 적절하다고 생각합니다.
norok2

2
이것은 bisect 모듈의 예입니다
dawg

작은 목록에도 불구하고 @schwobaseggl은 더 빠릅니다. 내 노트북에서 bisect 솔루션은 1.2µs, 루프는 1.5µs
Iftah

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에 의해 생성 된 점수 등급 쌍에 대해 생성기의 기본 인수와 함께 사용 됩니다 zip. 루프 접근 방식과 거의 동일합니다.


5

각 등급에 임계 값을 할당 할 수 있습니다.

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
Python 3.6 이하를 사용하는 경우 sorted(grades.items())dicts가 정렬되지 않을 수 있으므로 해야합니다 .
wjandrea

모든 Python 버전에서 안정적으로 작동하지는 않습니다. dict의 순서는 보장되지 않습니다. 또한 dict중요한 순서이므로 데이터가 불필요하게 무거운 데이터 구조이며 키가 아닌 인덱스 (순서)로 찾고 있습니다.
schwobaseggl

1
물론 가장 효율적이지는 않지만 모든 표시가 해당 임계 값에 가깝게 작성되므로 가장 읽기 쉽습니다. 차라리 dict을 쌍의 튜플로 바꾸는 것이 좋습니다.
norok2

@schwobaseggl이 특정 작업의 경우 예, 튜플 목록이 dict보다 낫지 만이 코드가 모두 모듈에 들어가면 dict은 문자 등급-> 임계 값을 조회 할 수 있습니다.
wjandrea

1
@wjandrea 무엇이든,와 같은 것을 허용하기 위해 키와 값을 교환해야 grades[int(score*10)/10.0]하지만 Decimal플로트는 악의적으로 악의적 인 dict 키로 사용해야 합니다.
schwobaseggl

5

이 특정한 경우 외부 모듈이나 발전기가 필요하지 않습니다. 몇 가지 기본 수학으로 충분하고 빠릅니다!

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"

2

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

2

이 문제를 해결하는 간단한 아이디어가 있습니다.

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

1

를 사용 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']

1

간단한 사례를 제공했습니다. 그러나 논리가 복잡해 지면 혼란을 처리하기 위한 규칙 엔진 이 필요할 수 있습니다 .

Sauron Rule 엔진을 사용 하거나 PYPI에서 일부 Python 규칙 엔진을 찾을 수 있습니다 .


1
>>> grade = lambda score:'FFFFFFDCBAA'[int(score*100)//10]
>>> grade(0.8)
'B'

1
이 코드는 질문에 대답 할 수 있지만 작동 방식과 사용시기를 설명하는 컨텍스트를 포함하는 것이 좋습니다. 코드 전용 답변은 장기적으로 유용하지 않습니다.
무스타파

0

재귀 접근법을 사용할 수도 있습니다.

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

0

보다 간결하고 이해하기 어려운 접근 방식은 다음과 같습니다.

첫 번째 솔루션은 math라이브러리 에서 바닥 기능을 사용해야 합니다.

from math import floor
def grade(mark):
    return ["D", "C", "B", "A"][min(floor(10 * mark - 6), 3)] if mark >= 0.6 else "F"

그리고 어떤 이유로 math라이브러리를 가져 오는 것이 당신을 귀찮게합니다. 바닥 기능에 대한 해결 방법을 사용할 수 있습니다.

def grade(mark):
    return ["D", "C", "B", "A"][min(int(10 * mark - 6) // 1, 3)] if mark >= 0.6 else "F"

이것들은 약간 복잡하며 진행중인 일을 이해하지 않으면 사용하지 않는 것이 좋습니다. 등급의 증분이 0.1이라는 사실을 이용하는 특정 솔루션은 0.1 이외의 증분을 사용하면이 기술을 사용하여 작동하지 않을 수 있습니다. 또한 마크를 등급에 매핑하기위한 쉬운 인터페이스가 없습니다. bisect를 사용하는 dawg와 같은 일반적인 솔루션이 더 적합하거나 schwobaseggl의 매우 깨끗한 솔루션 일 것입니다. 왜 내가이 답변을 게시하는지 잘 모르겠지만 파이썬의 다목적 성격을 보여주는 한 줄로 라이브러리가없는 문제를 해결하려는 시도 일뿐입니다 (라이브러리 사용이 나쁘다는 것을 말하려고하지는 않습니다).


0

받아쓰기를 사용할 수 있습니다.

암호

def grade(score):
    """Return a letter grade."""
    grades = {100: "A", 90: "A", 80: "B", 70: "C", 60: "D"}
    return grades.get((score // 10) * 10, "F")

데모

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

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

점수가 실제로 0과 1 사이이면 먼저 100을 곱한 다음 점수를 찾으십시오.


0

희망이 도움이되기를 바랍니다 : 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') else : 인쇄 ( 'F')


-3

당신은 숫자의 목록을 가지고 다음에 갈 성적 목록을 가질 수 있습니다 :

scores = (0.9, 0.8, 0.7, 0.6, 0.6)
lettergrades = ("A", "B", "C", "D", "F", "F")

그런 다음 지정된 점수를 문자 등급으로 변환하려면 다음을 수행하십시오.

item = 1 # Item 1 would be 0.8
scr = lettergrades[item]

그러면 최종 점수는입니다 "B".


3
경우 당신은 DV의에 대해 궁금 :이 솔루션은 같은 점수에서 얻을 수있는 방법 제공하지 않습니다 0.83등급에를 "B". 당신은 점수에서 색인으로 얻는 방법을 보여 주어야합니다 item.
schwobaseggl
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.