繰り返し

目標

プログラミングにおいては、条件分岐に並んで大事な制御に、繰り返しがある。
ここでは、JavaScriptの繰り返しについて学ぶ。
また、これまで何となく使ってきたブロックについて理解する。

  • 文とブロックについて理解する。
  • while文の挙動を理解することができる。while文を正しく書くことができる。
  • for文の挙動を理解することができる。for文を正しく書くことができる。
  • while文で書かれた繰り返しをfor文で書き直すことができる。
  • for文で書かれた繰り返しをwhile文で書き直すことができる。
  • continue文を使った繰り返しの挙動を理解できる。continue文を正しく使うことができる。
  • break文を使った繰り返しの挙動を理解できる。break文を正しく使うことができる。

文とブロック

前回、if文では次のような構文が使われると紹介した。
このif文の例では、波括弧「{」および「}」で囲まれた部分が実行されたりされなかったりする。

if (条件1) {
  /*
   *  条件1が成立する場合のみ実行される処理ブロック
   */
} else if (条件2) {
  /*
   *  条件1が成立せず、条件2が成立する場合のみ実行される処理ブロック
   */
} else if (条件3) {
  /*
   *  条件1〜条件2が成立せず、条件3が成立する場合のみ実行される処理ブロック
   */
...
} else if (条件n) {
  /*
   *  条件1〜条件n-1が成立せず、条件nが成立する場合のみ実行される処理ブロック
   */
} else {
   /*
    *  どの条件にも当てはまらない場合のみ実行される処理ブロック
    */
}

しかし、実はこの表現は必ずしも正しくない。
JavaScriptでは本来、if文の構文は次のようになっており、この「文」とされているところに実行したい文を記述する。

if (条件1)
  条件1が成立する場合のみ実行される文
else if (条件2)
  条件1が成立せず、条件2が成立する場合のみ実行される文
else if (条件3)
  条件1〜条件2が成立せず、条件3が成立する場合のみ実行される文
...
else if (条件n)
  条件1〜条件n-1が成立せず、条件nが成立する場合のみ実行される文
else
  どの条件にも当てはまらない場合のみ実行される文

JavaScriptでは、波括弧「{}」で括られた部分は1つの文として扱われるという約束がある。
そのため、初めに示したような書き方が可能となっている。
逆にいうとif文は波括弧を使わずに次のように書くことができるということである。
この例では、変数nが偶数なら「偶数です」、そうでなければ「奇数です」というメッセージを表示する。

if (n % 2 == 0)
  alert("偶数です");
else
  alert("奇数です");

繰り返し

while文

基本的な繰り返しのための制御文としてwhile文を紹介する。
while文はある条件が成り立っている間、処理を繰り返すものである。
書式は次のとおりである。

while (条件) 
   条件が成立する間、実行を繰り返す文

もちろん、次のように書くこともできる。

while (条件) {
  /*
   *  条件が成立する間、実行を繰り返す処理ブロック
   */
}

書式は単純なif文に良く似ている。
実際、「条件」の所に書く式はif文で使った条件式と同じものである。
while文では、まず条件を評価し、その条件が成立したら中括弧でくくられたブロックを実行する。
ここまでは動作もif文と同じである。
ただし、中括弧でくくられたブロックを実行し終わると、閉じ中括弧の後ろを実行するのではなく、一旦、条件の評価に戻る。
ここがif文と異なる所である。
フローチャートで描くと次のようになる。

while文の動作

では、実際に簡単な例を使って動作を確認してよう。
下記は、1から始めて順に値を2倍にして表示していくプログラムである。
値が100未満である限り繰り処理を返します。

var n = 1;
while (n < 100) {
  alert(n);
  n = n * 2;
}


このプログラムでは、始めにnを1にした後にwhile文に入る。
while文の中ではnが100より小さい場合には、まずその数字をポップアップで表示し、その後nを2倍して次の回に備える。
while文を1回目に実行する時はnは1だが、そのwhile文が終わる時には「n = n * 2」によってnが2倍され2になる。
nが2でも100よりは小さいので、もう一度while文の中括弧でくくられたブロックが実行される。
ここでは2と表示をした後に、再び「n = n * 2」が実行されnが4になる。
その後、nが128になるまで同じ部分が繰り返される。
nが128になった時点で2行目のwhile文の条件が成立しなくなるので、while文の後のブロックを抜け、プログラムは終了する。

繰り返し条件を間違えると延々と同じことが繰り返され、プログラムが終了しない状態になることがある。
このような状態のことを「無限ループ」と表現したりする。
無限ループ状態になると、ブラウザが応答しなくなるかもしれない。
このような場合は、一旦ブラウザを終了する。
キーボードの「command」「option」「esc」の3つのボタンを同時に押すと「アプリケーションの強制終了」画面が開くので、ここでブラウザを指定して終了する。
ブラウザを再起動した後に同じページを開いてしまうと、また無限ループに入ってしまうので、ページを開く前に当該ページを修正しなければならないことに注意が必要である。

do-while文

do-while文は、while文と似たような動作をするが、条件を評価する場所が異なる。
下記にdo-while文の書式を示す。

do 
  1回目と、条件が成立する間、実行を繰り返す文
while (条件);

下記のフローチャートをみて欲しい。
これはdo-while文のフローチャートである。
while文と比べると、条件を評価する部分が処理の下になっていることがわかる。
このため、do-while文を使うと、最低でも1回は処理が実行されるループを作る事が可能である。

do-while文の動作

do-while文はwhile文に比べると、あまり使われる頻度は多くない。
アルゴリズムにおいて、最低でも1回は実行しなければならないという状況が少ないためである。

for文

繰り返しを使う場合、ある変数をカウンタとして利用することが多々ある。
このような場合に便利なのがfor文である。
for文は、while文ではバラバラに書かなければならなかった、A.変数の初期化、B.条件、C.カウンタの操作、の3つをまとめて書けるような構文を提供している。
下記の2つ構文をみて欲しい。
これらは完全に等価なものである。

while文を使った例
A.初期化
while (B.条件) {
  /*
   *  条件が成立する間、実行を繰り返す処理ブロック
   */
  C.カウンタの操作;
}
for文を使った例
for (A.初期化; B.条件; C.カウンタの操作)
   条件が成立する間、実行を繰り返す文

それぞれを、具体的な例で書くと下記のようになる。

while文を使った例
var i = 0;
while (i < 10) {
  alert("ここが繰り返される。");
  i++;
}
for文を使った例
for (var i=0; i<10; i++)
   alert("ここが繰り返される。");

これはどちらもi=0からi=9まで10回処理ブロックを実行するというものである。
ここではfor文の「A.初期化」の部分でvarを使って同時に変数を定義しているが、これは次に示すように繰り返しの外側で行われても構わない。

var i;
for (i=0; i<10; i++) {
  /*
   *  条件が成立する間、実行を繰り返す処理ブロック
   */
}

また、for文の構文の中に「C.カウンタの操作」とあるが、ここには代入文を書く事も可能である。
例えば、カウンタを0、2、4、6、8と進めたければ次のように書くことができる。

for (var i=0; i<10; i=i+2) {
  /*
   *  条件が成立する間、実行を繰り返す処理ブロック
   */
}

i=i+2」は「i+=2」でも同じ意味になる。

カウンタを減らしていくことも可能である。
10、8、6、4、2のようにしたければ、次のように書く。
この例でも「i=i-2」を「i-=2」と書き直すことが可能である。

for (var i=10; i>0; i=i-2) {
  /*
   *  条件が成立する間、実行を繰り返す処理ブロック
   */
}

繰り返しの制御

繰り返しを使っていると、途中で繰り返しを止めたくなったり、今すぐに次の回に入りたくなったりすることがある。
このような時のためにJavaScriptでは、break文とcontinue文を提供している。

break文

繰り返しを途中で止めたい場合、break文を使うことによって条件に関係なく繰り返しから脱出することができる。

次のプログラムを見て欲しい。
このプログラムは、「男」または「女」という文字を10個入力し、それぞれの入力された回数を表示するものである。

var male = 0;
var female = 0;
for (var i=0; i<10; i++) {
  var gender = prompt("「男」または「女」を入力してください。");
  if (gender == "男")
    male = male + 1;
  else
    female = female +1;
}
alert("男性" + male + "人、女性" + female + "人です。");


この例では、必ず10個の文字を入力しなければならない。
これを途中で止められるようにするためにはどうすれば良いだろうか。
例えば、文字列「end」を入力すると、そこまでの合計を表示するようにするには次のようにする。

var male = 0;
var female = 0;
for (var i=0; i<10; i++) {
  var gender = prompt("「男」または「女」を入力してください。");
  if (gender == "end") break;
  if (gender == "男")
    male = male + 1;
  else
    female = female +1;
}
alert("男性" + male + "人、女性" + female + "人です。");


continue文

上の例では、「男」「end」以外の文字列を入力すると、女性としてカウントされてしまう。
ここで、「男」「女」「end」以外の文字列が入力されたらどちらにもカウントされないようにしたい。
そのためには、if文のelse節をelse ifにする方法もあるが、次のようにすることもできる。

var male = 0;
var female = 0;
for (var i=0; i<10; i++) {
  var gender = prompt("「男」または「女」を入力してください。");
  if (gender == "end") break;
  if (gender != "男" && gender != "女") continue;
  if (gender == "男")
    male = male + 1;
  else
    female = female +1;
}
alert("男性" + male + "人、女性" + female + "人です。");


この例ではcontinue文を用いることにより、「男」でも「女」でもない文字列が入力された場合には、カウント動作をせず、次の繰り返しに入るようになっている。
ここで、文字列「end」かどうかを調べる文の後に、continue文を含むif文があることに注意が必要である。
逆の順番だと、文字列「end」が入力されても、「男」でも「女」でもないので、繰り返しの先頭に戻ってしまう。

練習問題4-

while文を用いて、0から10までの数字の中で、偶数のみを「0, 2, 4, 6, 8, 10」とアラート表示するプログラムを作成しなさい。


練習問題4-

for文を用いて、0から10までの数字の中で、奇数のみを「1, 3, 5, 7, 9」とアラート表示するプログラムを作成しなさい。


練習問題4-

モンテカルロ法でN回試行し、円周率を求めるプログラムを作成しなさい。
ただし、N=100とする。また、基本的なモンテカルロ法での円周率の求め方は以下のとおりである。

  1. mを0にする。
  2. 1×1の範囲の任意の点(x,y)に点を打つ。
  3. その点の原点からの距離( SQRT(x2+y2))が1以下ならmに1加える。(ヒント:不等式の両辺を二乗しても同じなので、x2+y2が1以下であれば良い。)
  4. 2〜3をN回繰り返す。
  5. 1/4円の面積はπr2/4で、上記の場合r=1なのでπは4m/Nで求められる


練習問題4-

上記のモンテカルロ法のプログラムで、試行回数をプロンプトから入力できるようにしなさい。