採点システム機能の反復if-elifステートメントをどのように簡略化できますか?


20

目標は、スコアを「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')

より少ない引数を渡すことが可能である場合、それはさらに良いでしょう。



2
これはあなたの質問に答えますか?Pythonでグレーディングシステムを作成する方法
RoadRunner

回答:


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の方が高速です。私のラップトップでは、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())以前を使用している場合は、dictのソートが保証されていないため、使用する必要があります。
wjandrea

これは、すべてのPythonバージョンで確実に機能するとは限りません。辞書の順序は保証されないことに注意してください。また、a 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.selectnumpyライブラリから複数の条件を使用できます。

>> 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。これにより、1回の呼び出しで複数のスコアを処理するこの素晴らしいオプションが提供されます。

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
>>> 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ライブラリのインポートが煩わしい場合。あなたはfloor関数に回避策を使うことができます:

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の非常にクリーンな解決策です。なぜ私がこの答えを投稿しているのか本当にわかりませんが、Pythonの多用途な性質を示す1行でライブラリなしで問題を解決しようとする試みです(ライブラリの使用が悪いとは言いません)。


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:print( 'D')else:print( '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.