[Processing] 繰り返し処理

コンピュータを使う最大の利点の繰り返し処理です。一度正しい処理を確認した後に、同じ処理を複数回行いたい場合非常に便利です。人間では生涯かかっても処理しきれない作業を、瞬く間に行なってくれます。

処理を繰り返す

プログラムを記述する前に、現実世界の繰り返しの種類を考えてみると以下の2点が思い浮かびます

  1. 決まった回数を繰り返す
    • クラス全員の国語のテストの合計を求める
    • 飲み会の参加者に対して、参加費を回収する
  2. ある条件を満たすまで繰り返す
    • 所持金を超えるまで買い物をする
    • 袋詰セールで、袋から溢れるまで詰め込む

ふと思いつくだけで二点だけなので、本当はもっと多くの繰り返しの種類があるような気がしますが、とりあえずこの2点を抑えておけば問題はありません。さて、プログラミングで代表的な繰り返し処理のための命令がふたつあります。

  1. while命令
  2. for命令

です。Processingをはじめ、C言語に影響を受けた多くのプログラミング言語にはこの命令(もしくは似たような命令)があります。Processingでは記述方法の若干の差はありますが、この2つの命令に処理の差はありません。では、どのように使い分ければいいのでしょうか。使い方は個人個人で判断すれば良いのでしょうが、私は以下のように使い分けています

  1. 決まった回数を繰り返す : for命令
  2. ある条件を満たすまで繰り返す : while命令

これから簡単な使い方と、何故このような使い分けをするのかを簡単にメモしていきます。ちなみにこのような繰り返し処理は膨大なデータを処理するのに活用されることがおおく、特に配列との相性が良いのですが、配列の説明をしていませんので頑張って配列と切り離しています。ですので、例に若干無理が生じています。

while

whileは指定した条件が満たされている間、繰り返す命令です。以下のように記述します

while(条件)繰り返す処理;

繰り返す処理が複数の場合、中括弧を使ってブロックとして

while(条件){繰り返す処理;繰り返す処理;…繰り返す処理;}

ここで条件とはtrue(真)かfalse(偽)のどちらかの値です。条件が「true」の場合は繰り返す処理を行います。条件が「false」になると、繰り返しの処理を行わずに、while命令の次の処理へと移行します。条件では関係演算子を扱うことが多いでしょう。

例えば、「所持金を超えるまで買い物をする」という処理をしてみましょう。所持金は1000として、問題を簡単にするために、商品の単価を80で統一します。さて、いくつ目で1000を超えるでしょうか。

int money = 1000; // 所持金
int count = 0; // 買った商品の数
int price = 60; // 商品単価
while(money >= 0){ // 所持金が0円以上なら繰り返す
  count++; // 買った商品の数を一つ増やす
  money = money - price; // 所持金から、商品代金を引く
}
println(count+"個目で所持金を越えましたしました。");
println((count - 1) + "個を"+((count - 1) * price)+"で購入することが可能で、所持金は" + (money + price) + "残ります");
17個目で所持金を越えましたしました。
16個を960で購入することが可能で、所持金は40残ります

このように、所持金が0未満になるまで繰り返し、所持金が0よりも小さくなったら繰り返しを行わなくなりましたね。この例の場合、所持金が0未満になったということは、実際に購入できる数よりも一つ多く購入していることになりますから、購入可能個数と所持金を知りたい場合は、一つ前の状態にもどさなければなりません。

do – while

whileの親戚として、do – while命令がある。

do 繰り返す処理; while(条件);

繰り返す処理が複数の場合、中括弧を使ってブロックとして

do {繰り返す処理;繰り返す処理;…繰り返す処理;} while(条件);

このように記述する。このdo – whileは「条件の判定をする前に、一度繰り返し処理を行う」という繰り返し処理です。言葉だとわかりづらいので流れ図にしてみました。

while命令 do – while命令
while dowhile

このような違いがあります。

whileのまとめ

whileは条件が「true」の場合に繰り返し処理を実行します。例にあるように、繰り返し処理の結果が、条件の判断につながるような、”いつ終わるかわからない”処理にはwhile命令が適しています(と思っています)。この繰り返し処理の中で条件に関する情報を更新しなければ、常に条件が「true」となるのでいつまでも繰り返されます。このような終わらない繰り返し処理を「永久ループ」といい、ループの脱出方法が用意されていなければプログラムが暴走状態といえます。ですので、条件の更新には注意してください。

for

forも指定した条件が満たされている間繰り返す命令です。whileとの大きな違いは、カウンタの初期値の設定と、カウンタの更新設定が用意されているところでしょうか。以下のように記述します

for(カウンタ初期化; 条件; カウンタ更新)繰り返す処理;

繰り返す処理が複数の場合、中括弧を使ってブロックとして

for(カウンタ初期化; 条件; カウンタ更新)
{繰り返す処理; 繰り返す処理; …繰り返す処理;}

条件に関してはwhileと全く同じで、「true」のならば繰り返す処理を実行します。ここで、大きく違うのは、初期値とカウンタの更新です。for命令は「最初の状態」「条件」「更新」を一文で書くことで非常に読みやすい命令です。
「カウンタの更新」とは、for命令の条件は、基本的に数を数え上げるもしくは下げるためのカウンタを利用して、繰り返しますので、そのカウンタの増減の設定を意味しています。for命令は非常に読みやすい反面、初期化の方法が複雑であったり、更新方法が複雑な場合、逆に読みづらくなってしまいます。
そのため、for命令は「ここからここまで繰り返す」と範囲がわかっている場合に利用すると楽ではないでしょうか(と私は思っています)。

例のプログラムを考えてみましょう。例えば、1から5まで積算してみましょう。

int val = 0;
for(int i = 1; i <= 5; i = i + 1)
  val = val + i;
println("1から5まで積算した結果:"+val);
1から5まで積算した結果:15

さて、このプログラムはどのような順で働いているのかというと、記号に置き換えて説明すると

for((A),(B),(C))
    (D)
(E)

とすると、
(A),(B),(D),(C),(B),(D),(C),…(C),(B),(E)
のように、初めに初期化、次に条件判断(真だったら)、繰り返し処理、更新、条件判断(真だったら)…条件判断(偽だったら終了)、次の行へ
といった具合に繰り返します。このように、繰り返し処理と条件には関係性がない場合にはfor命令が適している(のではないかと思っている)。むしろ、繰り返しの処理の中でカウンタを変更すると大惨事になってしまいます。

for(int i = 1; i <= 5; i = i + 1)

このfor命令の行を確認いてください。カウンタ(= i)が全ての項目に関わっていますよね。このように初期化、条件、更新にカウンタが関わっている場合はfor命令が向いていると思いますが、それ以外の場合はwhile命令を使用するべきだと思っています。

for命令のまとめ

for命令は繰り返しをする範囲がわかっている場合に適しています。もちろんこの範囲はプログラムの状況によって変化するでしょうから、例の様に数値を直接打ち込むことは少ないと思いますが、初期値と更新値、条件が一度に見渡せる利点はその点にあると思っています。また、他の言語ではfor命令が配列の長さに対する処理だったりしますので、あながちこの使い方は間違ってはいないと思います。流れ図はwhile命令と同様なので割愛します。

まとめ

今回は繰り返しをまとめました。for命令かwhile命令の一つで事足りるのですが、何故2つ用意されているのかという私なりの答えが、今回の内容でした。きっとスーパープログラマーの方々が仕様を決めているのでしょうから、理由があるのでしょう。いつかきちんと勉強したいものです。

コメントを残す

メールアドレスが公開されることはありません。