ゼロからはじめるプログラミング講座の第二十五回です。前回の練習問題の追加解説とループ内ループの解説をしていきます。
変数とif内ifを使ってコードを改良しよう。
前回の練習問題2の解答例です。
for(var i=1; i<=5; i++){
var a = i * i
if(a <= 10 && a%2 == 0){
console.log(a + "A")
}else if(a <= 10 && a%2 != 0){
console.log(a + "B")
}else if(a > 10 && a%2 == 0){
console.log(a + "C")
}else if(a > 10 && a%2 != 0){
console.log(a + "D")
}
}
for文を使って1~5までの二乗を計算しその結果が10以下の偶数か奇数か、10位上の偶数か奇数かを調べるというものでした。
これでも良いのですがもっとクールな書き方、テクニックがあるので紹介しようと思います。まずは何度も同じ計算を行っている部分を変数化しましょう。
この場合 a%2 の部分です。if文で条件を調べる時に機械は毎回a%2の計算しています。
これを変数に入れてやることで計算回数を減らすことができます。コードを改良します。
for(var i=1; i<=5; i++){
var a = i * i
var b = a % 2
if(a <= 10 && b == 0){
console.log(a + "A")
}else if(a <= 10 && b != 0){
console.log(a + "B")
}else if(a > 10 && b == 0){
console.log(a + "C")
}else if(a > 10 && b != 0){
console.log(a + "D")
}
}
a%2を変数bに代入しました。これでif文の条件の中でも変数bを使えることになりa%2の計算をせずに結果だけを参照することができるようになりました。
このようにif else文では上から順番に条件を確認していきます。条件がtrue真でなければ次の条件を確認しにいきます。この場合は10より上で奇数の数字だと4回もa%2の計算を行うことになります。計算結果を変数化しておくことで計算回数は4回から1回に減らすことができます。このように同じ結果が得られても計算速度が変わることがあります。
if else文は条件がtrue真になるまで全ての条件を確認していく。ということを踏まえてこのコードをさらに改良することができると気づきましたか?
if内if文を使えば更にコードを改良できるので確認してみましょう。
for(var i=1; i<=5; i++){
var a = i * i
var b = a % 2
if(a <= 10){ // aが10以下の場合
if(b == 0){ // bが偶数の場合
console.log(a + "A")
}else{ // そうでない場合
console.log(a + "B")
}
}else{ // aが10より上の場合
if(b == 0){
console.log(a + "C")
}else{
console.log(a + "D")
}
}
}
まずaが10以上かそうでないかに分けます。そして次にbが偶数かそうでないかを調べます。これで全部のパターンを調べることができ同じ結果が得られます。
こうすることでaが10より上え奇数の場合でも条件確認が2回で済みます。
このように同じ結果が得られるが計算方法、プログラムを改良することをアルゴリズムの最適化と言います。アルゴリズムとは計算方法、順路のことです。
今回の振り分けではこのアルゴリズムで最適のようにも思えますがもっと試行数が増えたり結果に偏りが出る場合はどうでしょうか?
プログラムが大きくなるにつれて処理の高速化、軽量化の重要度は上がっていきます。
それには数学や物理の知識が必要になったりもします。アルゴリズムを考えるのは楽しくもありますが何ヶ月も考えても最適化できないこともあります。この話はまた機会があればします。
for内forループを使ってみよう。
関数内関数やif内ifがあったようにforブロックでも同じようにfor文が使えます。
今回は1~3までの数字と0~2までの数字を組み合わせた文字を作ってみます。
for(var i=1; i<=3; i++){
for(var m=0; m<=2; m++){
console.log(i+"-"+m)
}
}
1-1
1-2
2-0
2-1
2-2
3-0
3-1
3-2
書き方は問題ないですね?単純にfor文の中にfor文を入れただけです。
※外側のfor文を親ループ、内側のfor文を子ループと言うことにします。
結果を見て分かるように子ループを抜けたあとに2回めの親ループに突入しています。
for文は条件を確認してtrue真ならば{}内を処理してからインクリメント(i++)をしてもう一度条件を確認するのでこれは当然の結果と言えます。
重要なのは親ループと子ループで同じ変数を使わないようにすることです。
特に子ループ内で親ループの変数iを操作するときは注意しましょう。
例えばこのように親の変数iを操作すると親ループが無限ループになってしまいます。
※このコードは無限ループするので実行したい場合はフリーズに注意しましょう。
for(var i=1; i<=3; i++){
for(var m=0; m<=2; m++){
i = i - 1 // 親ループの変数iを減らして親ループが終わらないようにする。
}
}
このように子ループの中でも特殊なスコープは働いていないので親の変数iを操作することができます。for内for文を使うときは注意しましょう。
練習問題を解いてみよう。
- for内for文を使って1~3までの数字とa~cまでのアルファベットを1文字ずつ使って作れる文字を全てコンソールに表示しなさい。
正解するとこうなります。
a1
1b
b1
1c
c1
2a
a2
2b
b2
2c
c2
3a
a3
3b
b3
3c
c3
解答例はこうです。(マウスオーバーで表示)
for(var i=1; i<=3; i++){
for(var m=0; m<=2; m++){ // 3回ループできれば条件はなんでもいい
if(m == 0){
console.log(i + "a")
console.log("a" + i)
}else if(m == 1){
console.log(i + "b")
console.log("b" + i)
}else{
console.log(i + "c")
console.log("c" + i)
}
}
}
お疲れ様でした。現時点の知識ではこのようなコードになってしまいますが今後登場する配列というものを使えばもっと機能的にコードが書けるようになります。ですがまだ少し先のことなので、次回はカウントアップ処理を解説します。
次も頑張って記事を作るのでチャレンジしてください!
JavaScript #1/#2/#3/#4/#5/#6/#7/#8/#9/#10/#11/#12/#13/#14/#15/#16/#17/#18/#19/#20
∩∩
(´・ω・)
_| ⊃/(___
/ └-(____/
 ̄ ̄ ̄ ̄ ̄ ̄ ̄
来たら起こして。
⊂⌒/ヽ-、__
/⊂_/____ /
 ̄ ̄ ̄ ̄ ̄ ̄ ̄