【ITコラム】プログラム入門:制御構文 – if –

初めましての方も2回目の方もこんにちは。健康診断の結果と歳を考えてダイエット開始したIT事業本部のてらにしです。
入門シリーズ第一回では、「変数と型」についてお話しました。

入門シリーズ第二回は「制御構文 – if -」です。
どんな言語であれ、必須の処理ですので、プログラムを触る上では必ず出てきます。なお、言語によって後述の「else if」が「elif」になっていたり、構文の区切りが{}ではなく、インデント(行頭の空白)であったり等、多少書き方に差がありますが、ほぼほぼ変わりません。

ifとは

ifとは

ifとは、[もし~ならば]という意味の英語そのままですが、「もしも〇〇だったら、この処理をします。」という条件分岐の為の構文です。

また、同時に出てくるものとして elseifelse が存在します。こちらもelseが[それ以外、別の]といった意味の英語ですが、プログラム上も同様です。
elseifであれば、elseifの前に書かれていたifの条件を満たしていなかった場合に、ifと全く同じように「もしも〇〇だったら、この処理をします。」という動きになります。
elseの場合は、ifでもelseifでも当てはまらなかった場合の分岐となり、「どれにも当てはまらなかったら、この処理をします。」という動きになります。

ifだけで全部出来る?elseは不要?

ここまでの説明だと、ifでいっぱい書けばelseifelseも不要ですし、実際にそういった記述をしても問題なくプログラムは動きます。ですが、非常に見苦しく、無駄なリソースを使う事となってしまいます。

分かりやすいように文章でイメージしてみましょう。なお、使用言語によって書き方が変わりますが、下記はJavaを例にとって

       if(条件文1){
         処理1
       } else if(条件文2){
         処理2
       } else {
         処理3
       }

という書き方をします。
ifの後の()に書かれている条件文に当てはまった場合、{}内に書かれている処理を実行する。という意味になります。
また、ifelseifは上から順に判定され、条件に当てはまった場合、後続の条件の判定(及び処理)は実行されません。
ですので、例えば条件文1に当てはまった場合、処理1のみ実行されます。
同様に条件文2に当てはまった場合は、処理2のみ実行され、条件文1にも条件文2にも当てはまらなかった場合は、処理3のみ実行されます。

内容 : 商品が並んでいるかどうかによって、どれか1種類のみ購入する。
優先度と商品の種類は次の通り

優先度高

・チョコレート
・ガム
・アメ
・買いたいものが何も無い(何も買わない)

優先度低

ifのみの場合

▼文章で見た場合
もし、チョコレートが売っていたら、チョコレートを買う
もし、チョコレートが売っていなくて、ガムが売っていたら、ガムを買う
もし、チョコレートが売っていなくて、ガムも売っていなくて、アメが売っていたら、アメを買う
もし、チョコレートが売っていなくて、ガムも売っていなくて、アメも売っていなかったら、何も買わない
▼コードで見た場合

       if(チョコレートが売っていたら) {
           チョコレートを買う
       }
       if(チョコレートが売っていなくて、ガムが売っていたら) {
          ガムを買う
       }
       if(チョコレートが売っていなくて、ガムも売っていなくて、アメが売っていたら) {
           アメを買う
       }
       if(チョコレートが売っていなくて、ガムも売っていなくて、アメも売っていなかったら) {
           何も買わない
       }

elseifとelseも使った場合場合

▼文章で見た場合
もし、チョコレートが売っていたら、チョコレートを買う
それが無くて、ガムが売っていたら、ガムを買う
更にそれもなくて、アメが売っていたら、アメを買う
どれも無かったら、何も買わない
▼コードで見た場合

       if(チョコレートが売っていたら) {
           チョコレートを買う
       } else if(ガムが売っていたら) {
          ガムを買う
       } else if(アメが売っていたら) {
           アメを買う
       } else {
           何も買わない
       }

どうでしょうか?比べてみるとelse ifelseを使った方が大分すっきりしているのではないでしょうか。
別にifだけで良いじゃんと言って、上にあげたようなコードを書くときっと遠い目をされるので、条件文に指定する内容が出来る限り簡潔になるよう心掛けると良いかと思います。
なお、長いならifの例の条件文前半に書いてある「チョコレートが売っていなくて」などの文を除けば良いじゃんと安直にやると、全部の商品が売っていた場合、一つしか買わない予定なのに全部買ってしまうことになります。(過去一度だけですが生徒さんに、何故か全部の処理が実行されるんですが何故ですか?と聞かれたことがあります・・。)

順番には気を付けよう

さて、先ほどまでの例では、商品があった場合に一つだけ買うという内容でしたが、前もって優先度を条件として挙げていました。
その順番の通りに条件文を並べていけばよいのですが、誤って違う順番で書いてしまった場合はどうなるでしょうか。

    if(アメが売っていたら){
        アメを買う
    } else if(チョコレートが売っていたら) {
        チョコレートを買う
    }

このようにしてしまうと、たまたまアメが売っていなくてチョコレートが売られていた場合は、当初の予定通り第一優先のチョコレートが買えますが、
両方とも売られていた場合に、欲しかったチョコレートを買わずにアメを買ってしまうことになります。
そんなの間違える訳ないじゃんと思うでしょう? しかし、意外と初心者の一部の方ですが、うっかりやってしまっていて、思った通りに動かないが何故かと質問される事があります。

条件分岐文 switch-case

ここまで説明してきたif文の他に、条件によって処理が分岐する構文でswitch-case文というものがあります。
(※ありますと言いつつ、Pythonなどのswitch-case文が存在しない言語もあります。その場合はif文で頑張りましょう。)
大きな違いとしては、if文は条件文の中に好きな条件を羅列していけますが、switch-case文については、特定の値を元に複数の内容に分岐していきます。

なお、例によって言語によって多少の書き方が変わりますが、大体はこのような書き方をします。
内容:
順位によって、賞金を変えたい。
1位:1万円
2位:5千円
3位:1千円
その他:500円

    
    switch(順位){
      case 1:
        賞金 = 1万円;
        break;
      case 2:
        賞金 = 5千円;
        break;
      case 3:
        賞金 = 1千円;
        break;
      default:
        賞金 = 500円;
    }

このように、順位という変数の中身の値が、1だったら1万円、2だったら5千円・・というように特定の値(変数)がどのような状態かによって処理が分岐します。
ここで文中で突然出てきている「break」と「default」について説明します。
break」については、if文と違って、この処理はここまでで終わります。という宣言をしないと下に書かれている処理を順番に処理してしまいます。(自動でbreakを入れてくれる言語・バージョンもあります)
そこで、1位の処理は賞金に1万円をセットして終わりですよーとお知らせするために、賞金をセットしたすぐ後に「break」と記載しています。
もし、「break」をすべて書かなかった場合に順位が2として渡された場合は、下記のような流れになります。

  1. case 2に当てはまるので、賞金に5千円をセットする。
  2. case 2breakされなかったため、case 3の処理も実行し、賞金に1千円をセットする。
  3. case 3breakされなかったため、defaultの処理も実行し、賞金に500円をセットする。
  4. switch-case文に書かれている処理が全て終わった為、switch文を抜ける。

このような流れとなり、結果として2位の賞金として渡されるはずの5千円が最終的に500円になってしまっています。悲しいですね。

default」に関してはif文の「else」と同様で、どのcaseにも当てはまらなかった場合の処理となります。

ifとswitch-caseの使い分け

ここまでの内容を説明すると、「よし分かった。switch-caseは不要なんだ。」と言われることがあります・・・が、ちょっと待って下さい。
使い分けをすることで、見やすくかつ無駄が少なくなります。
例えば、先ほどの順位の話をする場合に、if文であれば2つ目の選択肢以降に順位以外の条件を入れることが出来る為、全ての分岐の条件を確認しないと落とし穴があるかもしれません。

    if(順位が1だったら){
        賞金 = 1万円
    }else if(順位が2位だったら)
        賞金 = 5千円
    }else if(順位が3位かつ、審判が恋人だったら){
        賞金 = 5千円
    }else{
        賞金 = 500円
    }

この例でみると、悪いことをしている人が居ますね。本来3位のはずが審判が恋人の場合は2位の賞金を貰ってる上に、3位を取っても審判が恋人じゃない場合は賞金が500円になってしまっています。
このように、switch-caseの場合は特定の値を基準にして分岐するのに比べ、if文ではそれぞれの分岐で自由に条件を設定出来てしまうことから、特定の値以外に条件があるのかを気にして確認しなければなりません。分岐条件を分かりやすくするのは保守面でも大事ですので、このような特定の値でのみ分岐する場合は積極的にswitch-case文を使用しましょう。

他にも、breakを意図的に入れないことで、同じ処理を書かずに済むメリットもあります。例えば、下記のような例です。

内容:
福袋の金額によって、商品を増やす

    switch(金額){
      case 5000円:
        カーディガン1枚を袋に追加
      case 3000円:
        Tシャツ1枚を袋に追加
      default:
        ハンカチを袋に追加
    }

これをif文で書くと

    if(金額が5000円){
        カーディガン1枚を袋に追加
        Tシャツ1枚を袋に追加
        ハンカチを袋に追加
    }else if(金額が3000円){
        カーディガン1枚を袋に追加
        Tシャツ1枚を袋に追加
        ハンカチを袋に追加
    }else{
        ハンカチを袋に追加
    }

となり、同じことを何度も書かないといけません。例えば、TシャツをGパンに変更しようと思った際、switch-case文では1か所変更で済みますが、if文の場合は2か所変更することになります。

余談ですが、上記をもしもif文でやる場合、せめて下記の形でやると書く量が減ります。似たような例は実際に運用されているコードでもたまに見かけますので意識してみるときっと誰かが幸せになります。

    ハンカチを袋に追加
    if(金額が5000円){
        カーディガン1枚を袋に追加
        Tシャツ1枚を袋に追加
    }else if(金額が3000円){
        カーディガン1枚を袋に追加
        Tシャツ1枚を袋に追加
    }

このようにif文に入れるまでもなく、共通処理の場合はifの外に出して初期値として入れたりしてしまいます。

まとめ

チャート

プログラムの基本となる条件分岐について、内容は単純ですが条件については少し考える必要があります。いかにシンプルで分かりやすい条件に出来るかを意識してみてくださいね。
これで入門シリーズ2回目の「制御構文 – if -」については終わります。次回は、ループ文・・の前に「配列とMAP」と題して複数の値を持てる型について触れていく予定です。

それでは、この辺で。
風邪に負けないよう楽しいプログラミングライフを!

てらにし
スノボと猫と日本酒をこよなく愛するエンジニア
オススメのお酒は三和酒造の臥龍梅 山田錦と、吉田酒造の手取川 名流