📝

[C#]点数によってランク文字列を返すコードを考えてみる

に公開

スコアによってランク文字列を返すメソッドを考えてみます。
「こういう場合三項式が便利!」と解説していた記事があったので、ふと、自分だったらどうするか……と徒然なるままに記事にしてみました。
とりあえずパッと思いついたものだけ紹介し、メリット・デメリットも考えてみます。

元々のコード

public static string GetScoreRank(float score)
{
    string answer;

    if (score >= 100)
    {
        answer = "SSS";
    }
    else if (score >= 99.5)
    {
        answer = "SS";
    }
    else if (score >= 99)
    {
        answer = "S";
    }
    else if (score >= 98)
    {
        answer = "AAA";
    }
    else if (score >= 95)
    {
        answer = "AA";
    }
    else if (score >= 90)
    {
        answer = "A";
    }
    else
    {
        answer = "NOT CLEAR";
    }

    return answer;
}

これがわからないのであればプログラマーは諦めるレベルの基本コード。
なお、if の羅列やネストしまくるコードは、プログラムがあまり得意じゃない人が書きがちなコードであり、メンテナンス性もいいとは言えないため、嫌われる傾向があります。

三項式

public static string GetScoreRank(float score)
{
    return   score >= 100   ? "SSS"
           : score >= 99.5f ? "SS"
           : score >= 99    ? "S"
           : score >= 98    ? "AAA"
           : score >= 95    ? "AA"
           : score >= 90    ? "A"
           : "NOT CLEAR";
}

確かにスッキリした記述!
ただ、C/C++ に馴染みがない人にはなにやってるかわからないかも。
ブレークで状況が確認できないのも初心者には向いてなさそうです。

switch のパターンマッチング構文

public static string GetScoreRank(float score)
{
    return score switch
    {
        >= 100   => "SSS",
        >= 99.5f => "SS",
        >= 99    => "S",
        >= 98    => "AAA",
        >= 95    => "AA",
        >= 90    => "A",
        _        => "NOT CLEAR",
    };
}

そういえば C# にはパターンマッチング構文なるものがあったなーと思い出し、試しに書いてみました。
三項式に近いですね。
こちらは、C#9 からの構文なので、三項式よりも馴染みはないかもしれませんが、ブレークは1行ごとに設定することができます。

元々のコードをアレンジ

public static string GetScoreRank(float score)
{
    string answer;

    if      (score >= 100)   answer = "SSS";
    else if (score >= 99.5f) answer = "SS";
    else if (score >= 99)    answer = "S";
    else if (score >= 98)    answer = "AAA";
    else if (score >= 95)    answer = "AA";
    else if (score >= 90)    answer = "A";
    else                     answer = "NOT CLEAR";

    return answer;
}

スッキリさせたいだけなら、正直これでもいいかと思ってしまいました。初心者でもわかりやすい。
「キータイプ数が多い」というのは、最近のエディターの補完機能を使えばそれほど気にもならないはず。


勝手に入力を補完してくれる


実は、最初のコードも苦にならない

ここまで書いて「どれも実用的ではない」と思ってしまった

プロジェクトの大きさにもよりますが、条件データとコードは分離したいと思ってしまいました。
私が実際にコードを書くなら、こんなコードになりそうです。

public static string GetScoreRank4(float score)
{
    var rankingTable = new (float score, string grade)[]
    {
        (100,   "SSS"),
        (99.5f, "SS"),
        (99,    "S"),
        (98,    "AAA"),
        (95,    "AA"),
        (90,    "A")
    };

    return rankingTable.FirstOrDefault(t => score >= t.score).grade ?? "NOT CLEAR";
}

中規模以上のプロジェクトであれば、rankingTable はプログラムから追い出す前提です。
json とか、unity なら Scriptable Object とか。
タプルだの Linq だの C# 由来のコードが苦手であればこういうコードでも……ちょっと面倒ですが。

class ScoreRank
{
    public float  Score;
    public string Grade;
    public ScoreRank(float score, string grade)
    {
        Score = score;
        Grade = grade;
    }
}

public static string GetScoreRank(float score)
{
    var rankingTable = new ScoreRank[]
    {
        new ScoreRank(100,   "SSS"),
        new ScoreRank(99.5f, "SS"),
        new ScoreRank(99,    "S"),
        new ScoreRank(98,    "AAA"),
        new ScoreRank(95,    "AA"),
        new ScoreRank(90,    "A")
    };

    foreach (var rank in rankingTable)
    {
        if (score >= rank.Score)
        {
            return rank.Grade;
        }
    }

    return "NOT CLEAR";
}

終わりに

三項式は、C# だとほぼ使う必要がありませんが、組み込み用途の C/C++ では現役かもしれませんね。
if がスッキリかけるのは確かで、私も局所的にはお世話になることがあります。

データとコードの分離も、マシンスペックに余裕がある開発環境ならではという気がしています。
そんなことしたら速度ロスに怯えるような厳しい環境であれば、データをプログラムに埋め込むことが正義になることもあるでしょう。

皆さんはどういうコードが好きですか? 色々と見直すきっかけになれば幸いです。

Discussion