3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

結局for文を使うのか?while文を使うのか?for文とwhile文の使い分け

Posted at

※この記事はCやJavaなどCライクな構文のfor文を持つ言語向けの記事です。Python等foreachな言語は対象外です。

今更のようですが、for文とwhile文の使い分け、プログラミングを始めたての頃には誰しも疑問に思ったことでしょう。

世の中の一般的な文献には、for文は繰り返し回数が明らかなときに使用するなどと書かれていることが多いようです。

しかしながら、自分としてはこの説明があまり腑に落ちませんでした。

今日プログラムを書いていて、この違いについてやっと自分の中で一つの落としどころが見つかったので、ここに記録しておこうと思います。

以下、JavaScriptで記述します。

class Iterator {
  index = 0;
  constructor(list) {
    this.list = list;
  }
  next() {
    return this.list[this.index++];
  }
}

const iterator = new Iterator([1, 2, 3, 4, 5]);

以上のような実装のIteratorクラスを用意します(実際にはファイルリストなどをイメージしてもらえれば良いです)。ここで、すべての要素を出力しつつ、要素の個数を数える処理を記述したいとします。当初、私は次のようなコードを書きました1

let count = 0, item;
while (item = iterator.next()) {
  console.log(item);
  count++;
}
console.log(`個数: ${count}`);

コードをより読みやすくするため、以下のように書き換えてみます。

let count, item;
for (count = 0; item = iterator.next(); count++) {
  console.log(item);
}
console.log(`個数: ${count}`);

書き換えてみたのですが・・・このコード、確かに短くはなっているのですが、非常に読み辛いと感じませんか?

恐らくこの理由は、私たちが

for (A; B; C) {}

という文を見たとき、無意識に

For A, while B, do C.

つまりAについて、Bの間、Cしなさいと読んでいるためだと思うのです。このため、実際の式をここに当てはめたとき、文章として成り立たないと強い違和感を覚えます。

もう少し踏み込んだ表現をするのであれば、意識する必要があるのはAの文、つまり初期設定式です。「for」という単語(=~について)が使われている以上、BやC、そしてブロック内の文は嫌でもこのAの部分に束縛を受けます。

先ほどのfor文の例に違和感があったのは、初期設定式は変数countの初期化に使用されているにもかかわらず、継続条件式やブロック内の文がcountと全く関係のないものだったからなのです。

まとめ

while文で表現可能な繰り返しのうち、for文で表現するべきものは

  • 繰り返し初期に実施すべき式が存在する
  • その式の主たる対象が継続条件や再設定式、ループ内の処理においても主要な要素である

を満たすものだということができると思います。

極端な例

逆に言えば、上のルールを満たしさえしていれば、一般に言われる「繰り返し回数がわかっている」を満たさない場合においても、for文を使って書けるものが存在することになります。以下の例はどうでしょうか。

class Iterator {
  index = 0;
  constructor(list) {
    this.list = list;
  }
  get currentItem() {
    return this.list[this.index];
  }
  next() {
    this.index++;
  }
}

let count = 0;
for (
  const iterator = new Iterator([1, 2, 3, 4, 5]);
  iterator.currentItem;
  iterator.next()
) {
  console.log(iterator.currentItem);
  count++;
}
console.log(`個数: ${count}`);

あまり違和感はない・・・ですよね???

  1. JavaScriptでは、配列の範囲外のインデックスにアクセスがあった場合、エラーとはならずundefinedというfalsyな値を返します。このため、nextメソッドは実行されるたびに要素を1つずつ返却し、全て終わるとundefinedを返すという挙動を示します。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?