26

私が大学で CS をとっていたとき (80 年代半ば)、常に繰り返されていたアイデアの 1 つは、常にループを記述し、ループの下部 (do ... while) ではなく上部 (while...) でテストすることでした。ループ。これらの概念は、多くの場合、トップでテストされたループが、ボトムでテストされたループよりも統計的に正しい可能性が高いことを示した研究への言及によって裏付けられました。

その結果、私はほとんどの場合、一番上でテストするループを書きます。コードがさらに複雑になる場合は行いませんが、そのようなケースはまれです。一部のプログラマーは、ほとんどの場合、最後にテストするループのみを作成する傾向があることに気付きました。次のような構造を見ると:

if (condition)
{
    do
    {
       ...
    } while (same condition);
}

またはその逆(ifwhile)、彼らが実際にそのように書いたのか、それともifループがnullケースを処理しないことに気付いたときにステートメントを追加したのか疑問に思います。

私はいくつかのグーグルをしましたが、この主題に関する文献を見つけることができませんでした. 皆さん (とギャル) はループをどのように書いていますか?

4

31 に答える 31

78

私は常に、0 回以上実行する必要がある場合は最初にテストし、1 回以上実行する必要がある場合は最後にテストするという規則に従います。あなたの例に記載されているコードを使用する論理的な理由はわかりません。複雑さが増すだけです。

于 2008-10-22T00:37:07.933 に答える
57

ループの最初の繰り返しの前に条件をテストする場合は、while ループを使用します。

ループの最初の反復を実行した後に条件をテストする場合は、do-while ループを使用します。

たとえば、次のスニペットのいずれかのようなことをしているとします。

func();
while (condition) {
   func();
}

//or:

while (true){
    func();
    if (!condition) break;
}

次のように書き換える必要があります。

do{
    func();
} while(condition);
于 2010-06-22T16:17:13.000 に答える
20

違いは、do ループは「do something」を 1 回実行してから条件をチェックして「do something」を繰り返す必要があるかどうかを確認するのに対し、while ループは何かを実行する前に条件をチェックすることです。

于 2008-12-24T01:51:37.427 に答える
17

do/を回避whileすると、コードが読みやすくなりますか?

いいえ。

do/ループを使用する方が理にかなっている場合はwhile、そうしてください。条件をテストする前にループの本体を 1 回実行する必要がある場合は、おそらくdo/whileループが最も簡単な実装です。

于 2010-07-31T02:30:47.277 に答える
12

条件が false の場合、最初の 1 つはまったく実行されない可能性があります。他のものは少なくとも 1 回実行され、条件を確認します。

于 2008-12-24T01:51:52.463 に答える
7

読みやすさのために、上部でテストするのが賢明なようです。これがループであるという事実は重要です。コードを読む人は、ループの本体を理解しようとする前に、ループの条件を認識しておく必要があります。

于 2008-10-22T00:50:03.227 に答える
6

これは、私が最近見つけた良い実例です。多数の処理タスク (配列内の要素の処理など) があり、存在する CPU コアごとに 1 つのスレッド間で作業を分割したいとします。現在のコードを実行するには、少なくとも 1 つのコアが必要です! do... whileしたがって、次のようなものを使用できます。

do {
    get_tasks_for_core();
    launch_thread();
} while (cores_remaining());

ほとんど無視できますが、パフォーマンス上の利点を考慮する価値があるかもしれません。標準ループとして同様に記述できwhileますが、常に評価される不必要な初期比較が常に行われtrue、シングルコアでは do-while 条件が分岐します。より予測可能です (標準の true/false を交互に使用するのに対して、常に false ですwhile)。

于 2010-06-22T16:55:10.983 に答える
4

最初は実行前に条件をテストするため、コードがその下のコードに入らない可能性があります。2 つ目は、条件をテストする前にコードを実行します。

于 2008-12-24T01:52:23.790 に答える
4

while ループは最初に「条件」をチェックします。false の場合、「何かをする」ことはありません。しかし、do...while ループは最初に「何かを実行」し、次に「条件」をチェックします。

于 2008-12-24T01:53:09.920 に答える
4

ええ、本当です。少なくとも 1 回は実行されます。それが唯一の違いです。これに関して他に議論すべきことは何もない

于 2010-06-22T16:18:41.970 に答える
4

はい、while の代わりに for を使用したり、for の代わりに foreach を使用したりすると読みやすさが向上します。そうは言っても、いくつかの状況ではwhileを行う必要があり、それらの状況を強制的にwhileループにするのはばかげていることに同意します。

于 2010-07-31T02:32:46.480 に答える
4

一般的な使用法について考えると、より役に立ちます。while ループの大部分はwhile、 で動作するように作成できたとしても、 で非常に自然に動作するdo...whileため、基本的には違いが問題にならない場合に使用する必要があります。したがってdo...while、読みやすさが著しく向上するまれなシナリオに使用します。

于 2010-07-31T02:32:53.550 に答える
3

私自身、do-whileループを好む傾向があります。ループの開始時に条件が常に真である場合は、終了時にテストすることをお勧めします。私の目には、(アサーション以外の)テスト条件の全体的なポイントは、テストの結果がわからないということです。条件テストが上部にあるwhileループを見ると、ループがゼロ回実行される場合を検討する傾向があります。それが決して起こらないのなら、それを明確に示す方法でコーディングしてみませんか?

于 2010-07-31T04:28:21.900 に答える
3

Piemasons が指摘したように、違いは、テストを実行する前にループを 1 回実行するか、ループの本体が実行されないように最初にテストを実行するかです。

重要な問題は、どちらがアプリケーションに適しているかです。

2 つの簡単な例を挙げると、

  1. 配列の要素をループしているとします。配列に要素がない場合、0 のうちの 1 を処理したくありません。したがって、WILE を使用する必要があります。

  2. メッセージを表示し、応答を受け入れ、応答が無効な場合は、有効な応答が得られるまで再質問します。だから必ず一度は聞きたい。応答が得られるまで応答が有効かどうかをテストできないため、条件をテストする前にループの本体を 1 回通過する必要があります。DO/WHILE を使用する必要があります。

于 2010-06-22T17:52:17.327 に答える
3

while()はループ本体の各実行前に条件をチェックし、do...while()はループ本体の各実行後に条件をチェックします。

したがって、**do...while()**s は常にループ本体を少なくとも 1 回実行します。

機能的には、while() は次と同等です。

startOfLoop:
    if (!condition)
        goto endOfLoop;

    //loop body goes here

    goto startOfLoop;
endOfLoop:

do...while() は次と同等です

startOfLoop:

    //loop body

    //goes here
    if (condition)
        goto startOfLoop;

実装はおそらくこれよりも効率的であることに注意してください。ただし、do...while() は while() よりも比較が 1 つ少ないため、わずかに高速です。次の場合は do...while() を使用します。

  • 条件が最初は常に true になることがわかっている場合、または
  • 最初は条件が false であっても、ループを 1 回実行する必要があります。
于 2008-12-24T02:15:35.070 に答える
3

翻訳は次のとおりです。

do { y; } while(x); 

と同じ

{ y; } while(x) { y; }

追加の中括弧は、 に変数定義がある場合に使用することに注意してくださいy。これらのスコープは、do-loop の場合のようにローカルに保持する必要があります。そのため、do-while ループはその本体を少なくとも 1 回実行するだけです。それ以外は、2 つのループは同一です。したがって、このルールをコードに適用すると

do {
    // do something
} while (condition is true);

do ループに対応する while ループは次のようになります。

{
    // do something
}
while (condition is true) {
    // do something
}

はい、do ループの対応する while が while とは異なることがわかります:)

于 2008-12-24T02:37:38.923 に答える
3

両者のユースケースは異なります。これは「ベスト プラクティス」の質問ではありません。

forまたはwhile を使用するよりも、排他的に条件に基づいてループを実行する場合

条件に関係なく一度何かを実行したい場合は、条件評価に基づいて実行を続けます。 一方を行います

于 2008-10-22T00:51:46.533 に答える
3

1 回以上ループする理由が思いつかない人のために:

try {
    someOperation();
} catch (Exception e) {
    do {
        if (e instanceof ExceptionIHandleInAWierdWay) {
            HandleWierdException((ExceptionIHandleInAWierdWay)e);
        }
    } while ((e = e.getInnerException())!= null);
}

同じことが、あらゆる種類の階層構造に使用できます。

クラス ノード:

public Node findSelfOrParentWithText(string text) {
    Node node = this;
    do {
        if(node.containsText(text)) {
            break;
        }
    } while((node = node.getParent()) != null);
    return node;
}
于 2008-10-22T12:03:27.520 に答える
2
while( someConditionMayBeFalse ){

// this will never run...

}


// then the alternative

do{

// this will run once even if the condition is false

while( someConditionMayBeFalse );

違いは明らかであり、コードを実行してから結果を評価して、「もう一度やり直す」必要があるかどうかを確認できます。また、whileの他の方法では、条件が満たされない場合にスクリプトのブロックを無視できます。

于 2012-02-10T00:34:25.800 に答える
2

コードを正しく書く方法を知っていれば、どちらの規則も正しいです:)

通常、2 番目の規則 ( do {} while() ) の使用は、ループの外側でステートメントが重複しないようにするためのものです。次の(単純化された)例を考えてみましょう。

a++;
while (a < n) {
  a++;
}

を使ってより簡潔に書くことができます

do {
  a++;
} while (a < n)

もちろん、この特定の例は、次のようにさらに簡潔に書くことができます (C 構文を想定)。

while (++a < n) {}

しかし、ここで要点がわかると思います。

于 2008-12-24T02:40:02.087 に答える
2

それは実際には別のことを意味しています。C では、 do - whileコンストラクトを使用して、両方のシナリオを実現できます (少なくとも 1 回実行し、true の場合に実行します)。しかし、PASCAL にはシナリオごとに繰り返し - untilwhileがあり、私の記憶が正しければ、ADA には途中で終了できる別の構造がありますが、もちろんそれはあなたが求めているものではありません。あなたの質問に対する私の答え: 私はループが一番上にテストされているのが好きです。

于 2008-10-22T00:50:28.423 に答える
1

私はほとんど独占的にトップでテストを書いています。コードが少ないので、少なくとも私にとっては、何かを台無しにする可能性が低くなります (たとえば、条件をコピーして貼り付けると、2 つの場所で常に更新する必要があります)。

于 2008-10-22T00:36:45.643 に答える
1

30 年前にそれを行うことで 1 つまたはいくつかのマシン サイクルを節約できたので、一部の人々は一番下でテストしていると思います。

于 2009-06-15T12:34:21.077 に答える
1

正しいコードを書くには、基本的に、正しさの精神的、おそらく非公式な証明を実行する必要があります。

ループが正しいことを証明するための標準的な方法は、ループ不変条件と帰納法を選択することです。ただし、複雑な言葉は飛ばしてください。非公式に行うことは、ループの各反復で真となる何かを把握することであり、ループが完了すると、達成したいことが真になるということです。ループの不変条件は、最後に false になり、ループが終了します。

ループ条件が不変条件にかなり簡単にマッピングされ、不変条件がループの先頭にあり、ループのコードを調べて、ループの次の反復で不変条件が真であると推測される場合、それは簡単です。ループが正しいことを確認します。

ただし、不変条件がループの最後にある場合、ループの直前にアサーションがない限り (良い方法です)、その不変条件がどうあるべきかを本質的に推測する必要があるため、より困難になります。ループの前に実行されたものは、ループの不変式を true にします (ループの前提条件がないため、コードはループ内で実行されます)。頭の中での非公式な証明であっても、正しいことを証明するのはますます難しくなります。

于 2009-06-15T12:34:52.150 に答える
1

これは本当の答えではありませんが、私の講師の 1 人が言ったことの繰り返しであり、当時私は興味を持っていました。

while..do と do..while の 2 つのタイプのループは、実際には 3 番目のより一般的なループのインスタンスであり、中間のどこかにテストがあります。

begin loop
  <Code block A>
  loop condition
  <Code block B>
end loop

コード ブロック A は少なくとも 1 回実行され、B は 0 回以上実行されますが、最後の (失敗した) 反復では実行されません。while ループはコード ブロック a が空の場合であり、do..while はコード ブロック b が空の場合です。しかし、コンパイラを作成している場合は、両方のケースをこのようなループに一般化することに関心があるかもしれません。

于 2009-06-15T12:39:27.240 に答える
1

それは、上でテストしたい状況、下でテストしたい状況、さらに途中でテストしたい状況に依存します。

しかし、与えられた例はばかげているようです。上部でテストする場合は、if ステートメントを使用せず、下部でテストします。while ステートメントを使用するだけです。それが目的です。

于 2008-10-22T00:56:41.593 に答える
1

最初に、テストをループ コードの一部と考える必要があります。テストがループ処理の開始時に論理的に属している場合、それはトップオブザループ テストです。テストが論理的にループの最後に属する場合 (つまり、ループを実行し続けるかどうかを決定する場合)、それはおそらくループの最後にあるテストです。

テストが論理的にそれらの中間に属している場合は、何か凝ったことをする必要があります。:-)

于 2008-10-22T01:50:26.960 に答える
0

コード生成に関する私の限られた知識から、コンパイラがループの最適化をより適切に実行できるようにするため、一番下のテスト ループを作成することをお勧めします。下部のテスト ループでは、ループが少なくとも 1 回実行されることが保証されます。これは、ループ不変コードが出口ノードを「支配」することを意味します。したがって、ループが始まる直前に安全に移動できます。

于 2010-05-27T20:25:16.893 に答える
0

コンピューター サイエンスの典型的な離散構造クラスでは、2 つの間に同等のマッピングがあることを簡単に証明できます。

スタイル的に、私は while (easy-expr) { } を好むのは、easy-expr が前もってわかっていて準備ができていて、ループでオーバーヘッドや初期化が繰り返されない場合です。私は { } while (somewhat-less-easy-expr); を行うことを好みます。より多くの繰り返しのオーバーヘッドがあり、条件を事前に設定するのはそれほど単純ではない場合があります。無限ループを書く場合は、常に while (true) { } を使用します。理由は説明できませんが、(;;) { } を書くのは好きではありません。

于 2008-12-24T02:32:04.490 に答える
0

if..do..while ループを記述するのは、コードのサイズが大きくなり、コードの重複が発生するという単純な理由から、悪い習慣だと思います。コードの重複はエラーが発生しやすいため、回避する必要があります。1 つの部分への変更は重複に対しても実行する必要がありますが、常にそうであるとは限りません。また、コードが大きいほど、CPU キャッシュの処理が難しくなります。最後に、null ケースを処理し、頭の痛みを解決します。

最初のループが根本的に異なる場合にのみ、do..while を使用する必要があります。たとえば、ループ条件 (初期化など) を渡すコードがループで実行される場合です。それ以外の場合、最初の繰り返しでループが発生しないことが確実な場合は、はい、do..while が適切です。

于 2009-06-15T13:01:05.193 に答える
0

一般に、コードの構造によって異なります。誰かがすでに答えたように、一部のアルゴリズムでは少なくとも 1 回の反復を実行する必要があります。したがって、追加の反復回数または少なくとも 1 回の反復が発生したフラグをエスケープするには、do/while を使用します。

于 2010-07-31T05:58:33.817 に答える