質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.61%

  • JavaScript

    15967questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

所得税の計算のような段階的に処理が変わる処理のエレガントな書き方

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,171

miu_ras

score 601

所得税の計算のような、入力値によって段階的に処理が変わる処理についての話です。

一応、何も考えずに実装したら以下のようなコードになりました。が、
・if文だらけ
・「税率・控除額・所得金額の範囲」は、しばしば変更される「データ」と言え、処理とデータが混在している状態である
ので、もっといい書き方がないかと思っています。

このような処理でのエレガントな書き方についてです。下記のコードは「ベスト」でしょうか?もっといい書き方がありますでしょうか?あなたならどう書きますか?

よろしくお願いします。


<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
</head>
<body>

所得<input type="text" id="input">円
<input type="button" id="btn" value="算出"><br>
税額<input type="text" id="result">円

<script>
jQuery(function ($) {

    function calcTax(income) {
        if (income == "" || isNaN(income) || income < 0) {
            return "";
        }
        var taxRate, deduction;
        if (income <= 1950000) {
            taxRate = 0.05, deduction = 0;
        } else if (income <= 3300000) {
            taxRate = 0.10, deduction = 97500;
        } else if (income <= 6950000) {
            taxRate = 0.20, deduction = 427500;
        } else if (income <= 9000000) {
            taxRate = 0.23, deduction = 636000;
        } else if (income <= 18000000) {
            taxRate = 0.33, deduction = 1536000;
        } else if (income <= 40000000) {
            taxRate = 0.40, deduction = 2796000;
        } else {
            taxRate = 0.45, deduction = 4796000;
        }
        return (income - deduction) * taxRate;
    }

    $("#btn").click(function() {
        $("#result").val(calcTax($("#input").val()));
    });
});
</script>

</body>
</html>
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+3

 データ駆動に変更することで if での分岐を少なくする方法があります。

calcTax2() にデータ駆動にしてみた例を書いています。
税額 は calcTax()、税額2 は calcTax2() の結果を表示しています。
(データとコードを分離するなら、 データ部分を別ファイに分けるとか、
 ajax でサーバーからデータを取得する などすることも考えられます。)
 
イメージ説明
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
  </head>
  <body>

    所得<input type="text" id="input">円
    <input type="button" id="btn" value="算出"><br>
    税額<input type="text" id="result">円
    税額2<input type="text" id="result2">円

    <script>
      jQuery(function ($) {
          function calcTax(income) {
              if (income == "" || isNaN(income) || income < 0) {
                return "";
              }
              var taxRate, deduction;
              if (income <= 1950000) {
                taxRate = 0.05, deduction = 0;
              } else if (income <= 3300000) {
                taxRate = 0.10, deduction = 97500;
              } else if (income <= 6950000) {
                taxRate = 0.20, deduction = 427500;
              } else if (income <= 9000000) {
                taxRate = 0.23, deduction = 636000;
              } else if (income <= 18000000) {
                taxRate = 0.33, deduction = 1536000;
              } else if (income <= 40000000) {
                taxRate = 0.40, deduction = 2796000;
              } else {
                taxRate = 0.45, deduction = 4796000;
              }
              return (income - deduction) * taxRate;
          }
          function calcTax2(income) {
            var data = [
                  // income,         taxRate, deduction
                  [ 1950000,         0.05, 0],
                  [ 3300000,         0.10, 97500],
                  [ 6950000,         0.20, 427500],
                  [ 9000000,         0.23, 636000],
                  [18000000,         0.33, 1536000],
                  [40000000,         0.40, 2796000],
                  [Number.MAX_VALUE, 0.45, 4796000],
              ];
              var idx = 0;
              for (var len = data.length; idx < len; idx++) {
                if (income <= data[idx][0]) {
                  break;
                }
              }
              return (income - data[idx][2]) * data[idx][1];
          }

          $("#btn").click(function() {
            $("#result").val(calcTax($("#input").val()));
            $("#result2").val(calcTax2($("#input").val()));
          });
       });
     </script>

  </body>
</html>

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/02/15 17:16

    割と素直な実装ですね。

    やっぱりこういう感じがいいですかね。
    ありがとうございました

    キャンセル

0

 ちょっと遊びました。
 if文なしです。ないだけですけれど。
function calcTax(income) {
  var taxRate = [
    {income:0, rate:0},
    {income:1950000, rate:0.05},
    {income:3300000, rate:0.10},
    {income:6950000, rate:0.20},
    {income:9000000, rate:0.23},
    {income:18000000, rate:0.33},
    {income:40000000, rate:0.40},
    {income:Infinity, rate:0.45}
  ].reverse()
  return taxRate.slice(0,-1).reduce(function(r, c, i){
    return {
      sum: r.sum + Math.max( r.income - taxRate[i+1].income, 0 ) * c.rate,
      income: Math.min( taxRate[i+1].income, r.income)
    }
  },{sum:0, income:income}).sum
}
 
 なお、本題から外れますが、その所得税の計算式間違えてますのでお気を付けください。控除はそこから引くんじゃないです。
所得税の税率|所得税|国税庁
 
 
 
追記
function calcTax(income) {
  return [
    {income:0, rate:0},
    {income:1950000, rate:0.05},
    {income:3300000, rate:0.10},
    {income:6950000, rate:0.20},
    {income:9000000, rate:0.23},
    {income:18000000, rate:0.33},
    {income:40000000, rate:0.40},
    {income:Infinity, rate:0.45}
  ].reverse().reduce(function(r, c){
    return {
      sum: r.sum + Math.max( r.income - c.income, 0 ) * r.prev.rate,
      income: Math.min( c.income, r.income),
      prev: c
    }
  },{sum:0, income:income, prev:{income:0, rate:0}}).sum
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/02/15 16:47

    累進課税専用のアルゴリズムという感じですかね。で、ちと分かりにくいですね。せっかくreduceを使っているのにさらに別途taxRateにもアクセスしていて。

    が、勉強になりました。ありがとうございました

    また控除計算のミス指摘、気づきませんでしたありがとうございました。

    キャンセル

  • 2015/02/16 10:16

    > で、ちと分かりにくいですね。
    ですね。
     
    > せっかくreduceを使っているのにさらに別途taxRateにもアクセスしていて。
    ちょっと書き換えてみましたので追記しておきます。
    分かりやすさも計算量もkatoyさんのコードの方が優れているだろうと思いますけど、関数型プログラミングっぽく書く遊びだと思っていただければ。

    キャンセル

0

※ここのシステムでは、「追記」に対して返事が書けない様なので(というか追記は一人一回に限られている?)、Lhankor_Mhyさん(2015/02/16 10:16)への返事をこちらに書きます。

なるほど、これが関数型っぽさなのですね。
関数型言語を勉強したことがないので、まだ私には「ぽさ」がよく分からないのですが。

とにかく自分の知るアプローチ法とはかなり異なり、理解するのに時間はかかりましたが勉強になりました。

ありがとうございました

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/02/18 01:43

    あと、一応解決済みにしておきますが、よりよいアルゴリズム等あればいつでも(1年後でも)追加で教えていただけるとうれしいです。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • JavaScript

    15967questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。