web-dev-qa-db-ja.com

forループで<または<=を使用する必要があります

ループを7回繰り返す必要がある場合、次を使用しますか?

for (int i = 0; i < 7; i++)

または:

for (int i = 0; i <= 6; i++)

2つの考慮事項があります。

  • 性能
  • 読みやすさ

パフォーマンスについては、JavaまたはC#。「より小さい」または「より小さいまたは等しい」が使用されているかどうかは重要ですか?異なる言語についての洞察がある場合は、どちらを示してください。

読みやすくするために、0ベースの配列を想定しています。

PD: 0ベースの配列についての私の言及は混乱させるかもしれません。配列要素を反復処理することについては話していません。ただの一般的なループ。

この魔法の数が何であるかを説明する定数を使用することについて、以下の良い点があります。したがって、「int NUMBER_OF_THINGS = 7」、「i <= NUMBER_OF_THINGS - 1 "変に見えますね。

124
Eugene Katz

1つ目は、より多くの idiomatic です。特に、反復回数を(0ベースの意味で)示します。 1ベースのもの(JDBC、IIRCなど)を使用する場合、<=を使用したくなるかもしれません。そう:

for (int i=0; i < count; i++) // For 0-based APIs

for (int i=1; i <= count; i++) // For 1-based APIs

実際のコードでは、パフォーマンスの差はごくわずかであると予想されます。

286
Jon Skeet

これらのループは両方とも7回繰り返されます。あなたが他に本当に理由がない限り、7が入っている方がより読みやすく/はっきりしています。

72
Steve Losh

私が大学で8086アセンブリを行ったときのことを覚えています。

for (int i = 6; i > -1; i--)

[〜#〜] jns [〜#〜] 操作があったため、符号なしの場合はジャンプを意味します。これを使用すると、各サイクル後に比較値を取得するためのメモリ検索が行われず、比較も行われませんでした。最近では、ほとんどのコンパイラーはレジスターの使用を最適化するため、メモリーはもはや重要ではなくなりますが、不要な比較を行うことができます。

ちなみに、ループに7または6を入れると、「 magic number 」が導入されます。読みやすくするために、Intent Revealing Nameの定数を使用する必要があります。このような:

const int NUMBER_OF_CARS = 7;
for (int i = 0; i < NUMBER_OF_CARS; i++)

編集:人々はアセンブリのものを得ていないので、より完全な例が明らかに必要です:

(i = 0; i <= 10; i ++)の場合、これを行う必要があります:

    mov esi, 0
loopStartLabel:
                ; Do some stuff
    inc esi
                ; Note cmp command on next line
    cmp esi, 10
    jle exitLoopLabel
    jmp loopStartLabel
exitLoopLabel:

(int i = 10; i> -1; i--)を行うと、これで逃げることができます:

    mov esi, 10
loopStartLabel:
                ; Do some stuff
    dec esi
                ; Note no cmp command on next line
    jns exitLoopLabel
    jmp loopStartLabel
exitLoopLabel:

確認したところ、MicrosoftのC++コンパイラはこの最適化を行いませんが、次の場合は行います。

for (int i = 10; i >= 0; i--) 

したがって、Microsoft C++†を使用していて、昇順でも降順でも違いがない場合は、使用する必要があるクイックループを取得するためのモラルがあります。

for (int i = 10; i >= 0; i--)

これらのいずれかではなく:

for (int i = 10; i > -1; i--)
for (int i = 0; i <= 10; i++)

しかし、「for(int i = 0; i <= 10; i ++)」の読みやすさを率直に取得することは、通常、1つのプロセッサコマンドが欠落するよりもはるかに重要です。

†他のコンパイラは異なることを行う場合があります。

55
Martin Brown

<= array.length-1より読みやすいため、常に<array.lengthを使用します。

また、7未満であり、インデックスが0から始まることがわかっている場合、その数は反復回数であることを直感的に理解できるはずです。

27
Omar Kooheji

最適化の観点から見ると、それは問題ではありません。

私が好むコードスタイルの観点から見た<。理由:

for ( int i = 0; i < array.size(); i++ )

よりもはるかに読みやすいです

for ( int i = 0; i <= array.size() -1; i++ )

また、<はすぐに反復回数を示します。

<に対するもう1つの投票は、多くの偶発的なオフバイワンのミスを防ぐことができるということです。

18
erlando

@ Chris、.NETでの.Lengthのコストの高さについてのあなたの声明は、実際には真実ではなく、単純型の場合は正反対です。

int len = somearray.Length;
for(i = 0; i < len; i++)
{
  somearray[i].something();
}

実際にはより遅い

for(i = 0; i < somearray.Length; i++)
{
  somearray[i].something();
}

後者は、ランタイムによって最適化されるケースです。ランタイムはiが配列への有効なインデックスであることを保証できるため、境界チェックは行われません。前者では、ランタイムはループの前にiが変更されなかったことを保証できず、インデックスルックアップごとに配列の境界チェックを強制します。

10
Jeff Mc

パフォーマンスに関しては、効果的な違いはありません。したがって、あなたが解決しようとしている問題の文脈で理解しやすい方を使用します。

6
Phil Wright

私が好む:

for (int i = 0; i < 7; i++)

これは、「ループを7回繰り返す」ことにより簡単に変換できると思います。

パフォーマンスへの影響についてはわかりません。違いがコンパイルされると思います。

5
Dominic Rodger

Java 1.5でできること

for (int i: myArray) {
    ...
}

配列の場合、心配する必要はありません。

4
JesperE

パフォーマンスの違いはないと思います。ただし、2番目の形式は間違いなく読みやすく、最後の反復数を見つけるために1つを暗記する必要はありません。

編集:他の人が同意しないようです。個人的には、ループ構造内の実際のインデックス番号を見るのが好きです。たぶん、Perlの0..6構文をより連想させるからだと思います。これは(0,1,2,3,4,5,6)と同等だと思います。 7が表示される場合、実際にインデックス7に到達しないことを確認するには、その隣の演算子をチェックする必要があります。

4
Adam Bellaire

私は「<7」バージョンを使用すると言います。なぜなら、それは大多数の人が読むものだからです。

「<」が「<=」より速いかどうかは気にしません。読みやすくするためだけに行ってください。

速度を上げたい場合は、次のことを考慮してください。

for (int i = 0; i < this->GetCount(); i++)
{
  // Do something
}

パフォーマンスを向上させるために、次のようにわずかに再配置できます。

const int count = this->GetCount();
for (int i = 0; i < count; ++i)
{
  // Do something
}

GetCount()がループから削除され(すべてのループでクエリされるため)、「i ++」が「++ i」に変更されていることに注意してください。

4
Mark Ingram

Edsger Dijkstra 記事を書いた 1982年のこのことについて、彼は下位<= i <上位を主張しています:

最小の自然数があります。 b)およびd)のように下限を除外すると、不自然数の領域に言及されているように、最小自然数から始まるサブシーケンスの下限が強制されます。それは見苦しいため、下限にはa)およびc)のように≤を優先します。ここで、最小の自然数から始まるサブシーケンスを考えてみましょう。上限を含めると、シーケンスが空の値に縮まるまでに、後者が強制的に不自然になります。それは見苦しいため、上限についてはa)およびd)のように<を優先します。慣例a)が優先されると結論付けます。

4
Martijn

C++では、!=は、すべてのSTLコンテナーで使用可能です。すべてのSTLコンテナイテレータが同等とは限りません。

4
madmoose

まず、6または7は使用しないでください。

使用する方が良い:

int numberOfDays = 7;
for (int day = 0; day < numberOfDays ; day++){

}

この場合、使用するよりも優れています

for (int day = 0; day <= numberOfDays  - 1; day++){

}

さらに良い(Java/C#):

for(int day = 0; day < dayArray.Length; i++){

}

さらに良い(C#)

foreach (int day in days){// day : days in Java

}

逆ループは確かに高速ですが、読みにくい(他のプログラマーではない場合)ので、避けるのが良いでしょう。特にC#、Java ...

3
Carra

この場合、7は理にかなっているという群衆の意見に同意しますが、6が重要な場合は、6番目のインデックスまでのオブジェクトにのみ作用していることを明確にしたい、と付け加えます。 <=の方が、6が見やすくなるため優れています。

2
tloach

大学に戻ると、これら2つの操作がCPUの計算時間で似ていることを覚えています。もちろん、私たちはアセンブリレベルで話しています。

ただし、C#またはJavaについて話している場合、一方が他方よりも速度が向上するとは思わない。得られる数ナノ秒は、導入する混乱の価値はほとんどないだろう。

個人的には、ビジネス実装の観点から意味のあるコードを作成し、読みやすいようにします。

2
casademora

これは "間違ったコードを間違ったようにする" のカテゴリに直接該当します。

JavaまたはC#の人々はindex < count条件のバリエーションに慣れているため、ゼロベースのインデックス言語では、この事実上の慣習を活用すると、さらに1つずつエラーが発生します。明らか。

パフォーマンスに関して:メモリフットプリントに値する優れたコンパイラは、問題なしなどとしてレンダリングする必要があります。

2
Ryan Delucchi

少し脇に置いて、.Netの配列またはその他のコレクションをループするとき、

foreach (string item in myarray)
{
    System.Console.WriteLine(item);
}

ループの数値よりも読みやすくするため。もちろん、これは実際のカウンターInt自体がループコードで使用されていないことを前提としています。パフォーマンスの変化があるかどうかはわかりません。

2
Rob Allen

<を使用する習慣を付けると、配列を反復処理するときに、読者と読者の両方に一貫性を持たせることができます。誰もが標準的な規則を持つ方が簡単です。また、0ベースの配列を持つ言語を使用している場合、<が規則です。

これはほぼ間違いなく、<と<=のパフォーマンスの違いよりも重要です。最初に機能と読みやすさを目指し、次に最適化します。

もう1つの注意点は、フェッチとインクリメントは一時的であり、インクリメントとフェッチは必要ないため、i ++よりも++ iを実行する方が良いことです。整数の場合、コンパイラーはおそらく一時的に最適化を行いますが、反復タイプがより複雑な場合は、できない場合があります。

1
JohnMcG

代わりに!=を使用することもできます。そうすることで、初期化でエラーが発生すると無限ループが発生し、エラーに早く気づき、それが原因で発生する問題がループ内でスタックすることに制限されますそれ)。

1
Brian

マジックナンバーを使用しないでください。

なぜ7ですか? (またはそのことについては6)。

使用する番号に合った正しい記号を使用してください...

その場合、私は使用する方が良いと思います

for ( int i = 0; i < array.size(); i++ )
1
Krakkos

いい質問ですね。私の答え:タイプAを使用( '<')

  • 反復回数が明確にわかります(7)。
  • 2つのエンドポイントの違いは、範囲の幅です
  • 文字が少ないほど読みやすくなります
  • 多くの場合、最後の要素のインデックスではなく、要素の総数i < strlen(s)を持っているため、均一性が重要です。

別の問題は、この構造全体にあります。 iと表示されるため、入力ミスをする可能性があります。 for-loop構文では、what to doではなくhow to doと記述されています。これを採用することをお勧めします:

BOOST_FOREACH(i, IntegerInterval(0,7))

これはより明確で、同じasm命令などにコンパイルされます。必要に応じてIntegerIntervalのコードを尋ねてください。

1

非常に多くの答えが...しかし、私は追加する何かがあると信じています。

私の好みは、リテラル数が明確に表示されることです「i」がループで取る値。したがって、ゼロベースの配列を反復処理する場合:

for (int i = 0; i <= array.Length - 1; ++i)

そして、配列を反復するのではなく、ループしているだけであれば、1から7までのカウントは非常に直感的です。

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

おそらくそれまでコンパイラーまたはランタイムがコードで何をするのかわからないので、読みやすさはプロファイルするまでパフォーマンスよりも優先されます。

1
Nick Westgate

人々が観察したように、あなたが言及した2つの選択肢のどちらにも違いはありません。これを確認するために、JavaScriptで簡単なベンチマークを行いました。

結果を見ることができます こちら 。これから明らかでないのは、1番目と2番目のテストの位置を入れ替えると、これら2つのテストの結果が入れ替わると、明らかにメモリの問題になるということです。しかし、反復の順序を逆にした3番目のテストは明らかに高速です。

1
David Wees

I <7と書く理由はたくさんあります。 7回繰り返すループに7番を入れるのは良いことです。パフォーマンスは事実上同じです。ほとんどすべての人がi <7と書いています。読みやすくするために書いている場合は、誰もがすぐに認識できる形式を使用してください。

1
DJClayworth

誰もが言うように、配列以外のものでも0インデックス付きイテレータを使用するのが慣例です。すべてが0で始まりn-1で終わり、下限が常に<=であり、上限が常に<である場合、以下のことを考える必要はありません。コードを確認するときに行います。

1
ephemient

「<」および「<=」演算子は、まったく同じパフォーマンスコストです。

「<」演算子は標準であり、ゼロベースのループで読みやすくなっています。

I ++の代わりに++ iを使用すると、C++のパフォーマンスが向上しますが、C#のパフォーマンスは向上しません。Javaについては知りません。

1
Jeff B

私は常に好んできた:

for ( int count = 7 ; count > 0 ; -- count )
1
kenny

速度差はありませんが、0ベースの配列を持つ言語では<の方が正しい可能性が高くなります。また、上ではなく下に繰り返す場合は、次のように言うことができます。

for (i = 7; --i >= 0; ) ...
0
Mike Dunlavey

少なくともx86コンパイラでは、パフォーマンスに違いはありません。私が知っているとすぐに、JLとJLEは同時に働きます。また、レッドアビリティについては、7つの要素の配列に「<7」を使用するのが理にかなっています。

0
akalenuk

<であるべきだと主張します。

少数の人が行うのに、なぜ多くの単語を使用するのか。 1つのテストは2つのテストよりも簡単に理解できます。その結果、今後の単体テストと変更が簡単になります。

違いは小さいですか?はい。しかし、それが保証されていないのに、なぜ複雑さを追加するのでしょう。

最後に、コードが最初から最適化されている場合、オプティマイザーやインタープリターの実装に依存しません。アインシュタインの言葉を引用すると、「できるだけシンプルに保ちますが、シンプルではありません」。

0
Cam Wolff

このイディオムは頻繁に繰り返されるため、最初の方法に従います。

for(int index = 0; index <array.length; i ++)

文字列s = oldString.substring(0、numChars);

等.

私は上限が除外されていることに慣れており、それを変更する正当な理由がない限り、そのままにしておくことを好みます。 (例-1ベースのインデックス付け)

0
Chris Cudmore

最初に読みやすくし、後で最適化します(ただし、正直なところ、顕著な違いは想像できません)。

0-> K形式は、配列を0ベースにすることでC#に持ち越されるCイディオムであることに注意してください。イディオムに従い、最も驚きの原則に違反しないでください。

0
plinth

私はこれが好きです:

for (int i = 0; i < 7; i++)

ただし(これは単なる考えです)、配列が0ベース(C#、Java)または1ベース(VB .NET)であるかどうかに関係なく、読みやすくする必要があります。私がこれを言うのは、0ベースの配列を操作すると、0-6が7回実行されるという考え方に陥るからです。 0-6は1-7よりも直感的だと思います。それから、私はC++、Java、C#のバックグラウンドから来ました。

0
Ryan Rodemoyer

.NETのような一部の言語/技術では、.Sizeまたは.Lengthまたはsize()/ length()を使用することは、反復するたびにそのプロパティにアクセスするので悪い考えです。

0
Chris S

どちらでも構いませんが、選択したらどちらか一方に固執します。 <=の使用に慣れている場合は、<を使用しないでください。逆も同様です。

私は<=を好みますが、ゼロから始まるインデックスで作業している状況では、おそらく<を使用しようとします。しかし、それはすべて個人的な好みです。

0
seanyboy

論理的な観点から厳密に言うと、< countが同等性をテストする正確な理由から、<= count<=よりも効率的であると考える必要があります。

0
Henry B

早すぎる最適化はすべての悪の根源です。 <<=よりも心配する本当に正当な理由がない限り、読みやすくしてください。

0
cciotti