【ワテのプログラミング講座】for/while/do-while/do-untilのどれが良い?

この記事は約9分で読めます。
スポンサーリンク

ワテがプログミラングを覚えた頃には FOR ループくらしか知らなんだ。

FOR I=1 TO 10 STEP 2
   PRINT "I=" + I
NEXT I

みたいなBASIC言語だ。

その後、FORTRAN, C, VB.NET, C#, C++ などの言語を覚えたのだが、それらのプログラミング言語の学習の過程で悩んだ事が有る。

それは、冒頭の FOR ~ NEXT ループ以外にいろんなループが出て来るのだ。

具体的には、以下の通り。

 

forループに関しては、

for(int i=0;i<10<i++){ ... }   // C#, C, C++, etc

foreach(var item in array){ ... }  // C#, etc

をよく使う。特に前者のindex方式がワテ好みだ。

 

一方、whileループに関しては、

while(){ ... }

do{ ... } while()

do{ ... } until()

などがあるが、どれを使ったら良いのか分からない。

 

その後のワテは、長年のプログラミング経験を経て現在ではwhile系ループ処理に関しては一種類だけのループ処理を使っている。

この記事では、各種のループ処理を比較しながら、最終的にワテが現在使っているその唯一のループ処理がどれなのか?なぜそれだけで良いのかなどを解説したい。

 

スポンサーリンク
ワテ推薦のプログラミングスクールで学ぶ
スポンサーリンク
スポンサーリンク

ループで処理するデータの準備

以下では配列の中身をループ処理で順番に表示すると言う単純な処理をしている。

正確に言うと配列ではなくてリストList<int>だ。要するに整数型のリスト。

使用言語はC#

そのリストデータは以下の通り。

10個の要素 0, 1, 4, 9, 16, 25, 36, 49, 64, 81 を持つリストを作っておく。

   List<int> lst = Enumerable.Range(0, 10).Select(x => x * x).ToList();

このリスト lst のデータを以下では各種のループで出力してみる。

なお、この lst データ自体には深い意味は無い。

最近C#のLINQに凝っていて、こんなやり方を覚えたので使ってみたかっただけだ。

なので、

   for (int i = 0; i < 10 ; i++ )
   { 
      lst.add(i*i);
   }

と書いても同じ。

 

さて、C#の最初のループは普通の for ループだ。

普通の for(int i=0;i<imax;i++){…} ループ

   for (int i = 0; i < lst.Count; i++)
   {
       Console.WriteLine("i={0}, lst[{0}]={1}", i, lst[i]);
   }   

実行してみる。

先ほど作成した List<int> lst を順番に出力するだけの簡単なC#プログラムだ。

実行結果
--- for loop ---------
i=0, lst[0]=0
i=1, lst[1]=1
i=2, lst[2]=4
i=3, lst[3]=9
i=4, lst[4]=16
i=5, lst[5]=25
i=6, lst[6]=36
i=7, lst[7]=49
i=8, lst[8]=64
i=9, lst[9]=81

まあこれは分かり易い。

開始と終了の条件を指定して決まった回数だけループする。

必要なら途中で

   if(条件) break;

を入れておけばループの中断も出来る。

 

次はwhileだ。

While(条件){ … }

   int i = 0;
   while (i < lst.Count)
   {
      Console.WriteLine("i={0}, lst[{0}]={1}", i, lst[i]);
      i++;
   }    

このループも良く知られているが、実はワテはあまり使わない。

実行結果は上のforループの場合と同じなので割愛する。

 

whileループでワテが良く使うのはこちらだ↓

while(true){ 先頭break }

   int i = 0;
   while (true)
   {
      if (i >= lst.Count)
      {
         break;
      }
 
      Console.WriteLine("i={0}, lst[{0}]={1}", i, lst[i]);
      i++;
   }      

まあ一つ前の while (i < lst.Count) の条件判定部分を否定形に変えて { … } の中の先頭に持ってきただけだ。

で、while(true) で { … } に入った直後に if(条件)break; するので動作としては 一つ前の

   while(条件){
      処理
   }

と全く同じ。

 

まあ while(true)とか for(;;) の無限ループを嫌う人もいるかも知れないが、ワテの場合にはこのループをよく使う。

   while(true){
      if(条件) break;
      処理
   }

理由は後述したい。

 

さて、ループと言えばもう一つある。

do{…} while(条件);

   int i = 0;
   do
   {
      Console.WriteLine("i={0}, lst[{0}]={1}", i, lst[i]);
      i++;
   } while (i < lst.Count);
  

こんなやつだ。

親戚には do~Untilと言うのも有る。C#では無いがVBAだったかな。

 

プログラミングの解説サイトでは、この末尾whileループに関しては必ず一回はカッコ内の処理を実行すると書いてある。

なので取り合えず一回処理したあとで条件判定するならこのループが適しているとも書いてある。

 

確かにそうなのだが、ワテの場合には、このループは今では絶対に使わない

理由は何故か?

それは、以下の理由による。

while(true){ 末尾break }と同じだから

   int i = 0;
   while (true)
   {
       Console.WriteLine("i={0}, lst[{0}]={1}", i, lst[i]);
       i++;
       if (i >= lst.Count)
       {
           break;
       }
   }

while(true) ループは先ほど登場したが、今の場合には同じwhile(true)ループだがカッコ内の処理の末尾に break の為のif(条件)を入れている。

こうしておくと、これは一つ前に説明した do{…}while(条件); と全く同じ動きになるのだ。

ただし、両者を比較すると条件部分が互いに否定関係になるが、その事自体は何ら問題は無い。

 

要するに、

ワテが以下の二つのループは使わずに、

   // 1A
   while(条件){    // 冒頭で判定。処理を一回も実行しない場合もある。
      処理
   }

 

   // 2A
   do{
      処理
   }while(条件);   // 末尾で判定。処理は必ず一回は実行する。

 

以下の二つのループを使う理由は、

   // 1B (1Aと同じ動き)
   while(true){    // 冒頭で判定。処理を一回も実行しない場合もある。
      if(条件) break;
      処理
   }

 

   // 2B (2Aと同じ動き)
   while(true){
      処理
      if(条件) break;
   }             // 末尾で判定。処理は必ず一回は実行する。

この while(true){…} を一つ覚えておけば、if(条件)break; の位置を変えるだけでどちらのループにも出来るからだ。

 

あるいは、

   // 3
   while(true){
      処理1
      if(条件) break;
      処理2
   }

などとすると、より柔軟性のある記述が可能となる。

ただし、この手法3は混乱し易い場合もあるので、基本はループ内の先頭あるいは末尾でのbreak脱出をお勧めする。

以上がワテ流のループ記述方法だ。

 

本格的にプログラミングを勉強したい人は有料だけれどこういうオンライン学習サイトもお勧めだ。

プログラミングを独学するのはかなりの忍耐力が必要だ。挫折する人も多い。

それに比べれば、講師の人から教えて貰える学習サイトは遥かに効率よく学べる。ただし有料だけれど。

まとめ

ここで紹介した手法は、あくまでワテ流なので世間一般の常識かどうかは未確認だ。

ワテの場合、条件後置きの do{…}while(条件); を覚えた頃には、プログラミングをしていて何らかのループ処理の場面に来た時に、

   while(条件){    // 1A
      ...
   }
   do{            // 2A
      ...
   }while(条件);

このどっちのループを使うべきかで悩んだ。

1A方式で書いていて、いや待てよ。一回は処理したいので2Aを使うべき?

などと混乱して、ループの記述を変えた経験が何度もある。

そう言う場合は、アルゴリズム自体が頭の中で十分に完成していないので、即席でループ構造を変更したりすると益々泥沼状態になる(ワテの経験に基づく)。

 

しかしながら、上で説明した

   // 3
   while(true){
      処理1
      if(条件) break;
      処理2
   }

方式のループを使う事に統一した今では、そんな事で悩む必要は無くなった。

必要に応じて if(条件)break; の位置を変えるだけなので、どっちのループを使うべきかなどと言う横道に逸れて思考が中断する事なく、本来のプログラミング作業に集中出来る。

と言う事で、あながちヘンテコな手法では無いと思っている。

ご意見、コメントなどありましたらお知らせ下さい。

有名な本だがワテは読んだ記憶が無い。

読んだかも知れないが全く記憶にない。

プログラムは芸術なのか?

スポンサーリンク
ワテ推薦のプログラミングスクールで学ぶ
コメント募集

この記事に関して何か質問とか補足など有りましたら、このページ下部にあるコメント欄からお知らせ下さい。

プログラミング
スポンサーリンク
warekoをフォローする
スポンサーリンク
われこ われこ

コメント