应该在for循环中使用<或<=
如果你不得不遍历一个循环7次,你会使用:
for (int i = 0; i < 7; i++)
要么:
for (int i = 0; i <= 6; i++)
有两个考虑因素:
- 性能
- 可读性
为了performance我假设Java或C#。 如果使用“小于”或“小于或等于”,这是否重要? 如果你有不同的语言洞察力,请指出。
为了可读性,我假设了基于0的数组。
UPD:我提到基于0的数组可能会使事情混淆。 我不是在讨论数组元素的迭代。 只是一个普遍的循环。
下面有一个好的一点是使用一个常数来解释这个幻数是什么。 所以,如果我有“ int NUMBER_OF_THINGS = 7
”,那么“ i <= NUMBER_OF_THINGS - 1
”看起来很奇怪,不是吗?
第一个更习惯 。 特别地,它表示(基于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
我希望在现实世界的代码中,性能差异是微不足道的。
这两个循环迭代7次。 我会说7中的那个更可读/更清晰,除非你对另一个有很好的理由。
我记得在我们大学时代做8086集会的时候,做这件事更有效率:
for (int i = 6; i > -1; i--)
因为有一个JNS的操作,这意味着如果没有迹象跳。 这意味着在每个周期之后没有内存查找来获得比较值,也没有比较。 现在大多数编译器都优化了寄存器的使用情况,所以内存不再重要,但是你仍然得到一个不需要的比较。
顺便把7或6放在你的循环中引入一个“ 幻数 ”。 为了更好的可读性,您应该使用意图显示名称来使用常量。 喜欢这个:
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:
我刚刚检查过,微软的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 ++)”的可读性通常比丢失一个处理器命令更重要。
†其他编译器可能做不同的事情。
我总是使用<array.length,因为它比<= array.length-1更容易阅读。
也有<7,并且假定您知道它以0索引开始,那么数字就是迭代次数应该是直观的。
从优化的angular度来看,这并不重要。
从代码风格的观点看,我更喜欢<。 原因:
for ( int i = 0; i < array.size(); i++ )
比这更可读
for ( int i = 0; i <= array.size() -1; i++ )
也给你直接的迭代次数。
另一个投票是,你可以防止大量意外的错误。
@Chris,关于.Length在.NET中昂贵的陈述实际上是不真实的,在简单types的情况下则完全相反。
int len = somearray.Length; for(i = 0; i < len; i++) { somearray[i].something(); }
实际上是比慢
for(i = 0; i < somearray.Length; i++) { somearray[i].something(); }
后者是由运行时优化的一种情况。 由于运行时可以保证我是一个有效的索引进入数组没有边界检查完成。 在前者中,运行时不能保证我在循环之前没有被修改过,并且强制检查数组中的每个索引查找。
我更喜欢:
for (int i = 0; i < 7; i++)
我认为这更容易翻译成“迭代7次循环”。
我不确定性能的影响 – 我怀疑任何差异都会被编辑掉。
在性能方面,它没有任何有效的区别。 因此,我会在你正在解决的问题的背景下使用哪一个更容易理解。
在Java 1.5中,你可以做
for (int i: myArray) { ... }
所以对于数组的情况下,你不必担心。
我不认为有性能差异。 第二种forms肯定更具可读性,但是你不必从头脑中减去一个来find最后一个迭代数字。
编辑:我看到别人不同意。 就我个人而言,我喜欢在循环结构中看到实际的索引号。 也许是因为它更像Perl的0..6
语法,我知道它相当于(0,1,2,3,4,5,6)
。 如果我看到一个7,我必须检查旁边的操作员看到,实际上,索引7是永远不会到达。
我会说使用“<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”。
在C ++中,我更喜欢使用!=
,它可用于所有STL容器。 并不是所有的STL容器迭代器都比不上。
Edsger Dijkstra在1982年写了一篇文章 ,他认为<= i <upper:
有一个最小的自然数。 排除b)和d)中的下界 – 强制从最小自然数开始的子序列,如上所述的下界进入非自然数的范围。 这是丑陋的,所以对于下限,我们更喜欢≤和a)和c)一样。 现在考虑从最小的自然数开始的子序列:包含上限将迫使后者在序列缩小到空的序列时是不自然的。 这是丑陋的,所以对于上限,我们更喜欢<a)和d)。 我们认为,惯例a)是首选。
首先,不要使用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 …
我同意人群说7这个例子是有道理的,但是我想补充说的是,在6是重要的情况下,比如说你想清楚你只是在第6个索引的对象上行事,那么因为它使得6更容易看见,所以<=更好。
回到大学的时候,我记得这两个操作在CPU上的计算时间是相似的。 当然,我们正在讨论组装层面。
但是,如果你正在谈论C#或Java,我真的不认为其中一个会提高速度,你得到的几纳秒很可能不值得你引入任何混淆。
就个人而言,我会编写从业务实现angular度来看有意义的代码,并确保它易于阅读。
这直接属于“使错误代码错误”的类别。
在基于零的索引语言中,例如Java或C#人员习惯于index < count
条件的变化。 因此,利用这种事实上的惯例会使错误的错误更加明显。
关于性能:任何值得其内存占用的优秀编译器都应该呈现诸如非问题。
作为一个轻微的一边,当在一个数组或其他集合在.Net中循环时,我发现
foreach (string item in myarray) { System.Console.WriteLine(item); }
比数字循环更可读。 这当然假定实际的计数器Int本身不被用在循环代码中。 我不知道是否有性能改变。
我写作<7的原因有很多。 在循环中迭代7次的数字7是好的。 性能是完全相同的。 几乎每个人都写我<7。 如果您为了可读性而写作,请使用每个人都会立即识别的表单。
我一直首选:
for ( int count = 7 ; count > 0 ; -- count )
当你迭代一个数组时,习惯使用<将会使你和读者保持一致。 每个人都有一个标准的约定会更简单。 如果您使用的是基于0的数组的语言,那么<是惯例。
这几乎肯定比<和<=之间的任何性能差异更重要。 首先要实现function性和可读性,然后进行优化。
另外需要注意的是,最好是习惯于++ ++而不是+++,因为读取和增量需要一个临时的,而增量和读取则不需要。 对于整数,你的编译器可能会优化暂时的,但如果你的迭代types更复杂,它可能无法。
不要使用幻数。
为什么是7? (或6件事)。
使用正确的符号为您要使用的号码…
在这种情况下,我认为使用更好
for ( int i = 0; i < array.size(); i++ )
“<”和“<=”运算符的性能成本完全相同。
“<”运算符是一个标准,更容易在基于零的循环中读取。
使用++而不是i ++可以提高C ++中的性能,但不能在C#中 – 我不了解Java。
正如人们所观察到的,你提到的两种select都没有区别。 为了证实这一点,我在JavaScript中做了一些简单的基准testing。
你可以在这里看到结果。 不清楚的是,如果我把第一次和第二次testing的位置交换,这两个testing的结果交换,这显然是一个记忆问题。 然而第三个testing,其中我反转迭代的顺序显然更快。
正如大家所说,通常使用0索引的迭代器,甚至是数组之外的东西。 如果一切从0
开始到n-1
结束,下限总是<=
且上限总是<
,那么在审查代码时就不用多想了。
伟大的问题。 我的答案是:使用typesA('<')
- 你清楚地看到你有多less次迭代(7)。
- 两个端点之间的差异是范围的宽度
- 较less的字符使其更具可读性
- 你更经常有元素的总数,而不是最后一个元素的索引,所以一致性很重要。
另一个问题是整个结构。 i
出现了3次 ,所以可能错误input。 for-loop构造说明如何去做,而不是做什么 。 我build议采用这个:
BOOST_FOREACH(i, IntegerInterval(0,7))
这更清楚,汇编相同的指令等。如果你喜欢,请求我的代码IntegerInterval。
这么多的答案…但我相信我有一些东西要补充。
我的首选是字面数字清楚地显示什么值“我”会在循环中 。 所以在迭代通过一个从零开始的数组的情况下:
for (int i = 0; i <= array.Length - 1; ++i)
如果你只是循环,而不是迭代数组,从1到7的计数是非常直观的:
for (int i = 1; i <= 7; ++i)
可读性胜过性能,直到你分析它为止,因为在那之前你可能不知道编译器或者运行时将会怎样处理你的代码。
你也可以使用!=
来代替。 这样,如果在初始化过程中出现错误,会导致无限循环,导致错误被更早地发现,并且会导致任何问题被限制在循环中(而不是稍后会出现问题,它)。
我认为或者没问题,但是当你select时,坚持一个或另一个。 如果您习惯于使用<=,则尽量不要使用<,反之亦然。
我更喜欢<=,但是在使用从零开始的索引的情况下,我可能会尝试使用<。 尽pipe如此,这完全是个人偏好。
严格来说,从逻辑的angular度来看,你必须认为< count
会比<= count
更有效,因为<=
也将testing相等的确切原因。