循环中的最后一个元素是否值得单独处理?

xto*_*ofl 19 language-agnostic loops for-loop control-structure while-loop

在审阅时,我有时会遇到这种循环:

i = begin
while ( i != end ) {    
   // ... do stuff
   if ( i == end-1 (the one-but-last element) ) {
      ... do other stuff
   }
   increment i
}
Run Code Online (Sandbox Code Playgroud)

然后我问这个问题:你会写这个吗?

i = begin
mid = ( end - begin ) / 2 // (the middle element)
while ( i != end ) {    
   // ... do stuff
   if ( i > mid ) {
      ... do other stuff
   }
   increment i
}
Run Code Online (Sandbox Code Playgroud)

在我看来,这超过了编写循环的意图:你循环,因为每个元素都有一些共同点.使用此构造,对于某些元素,您可以执行不同的操作.因此,我总结说,您需要为这些元素单独的循环:

i = begin
mid = ( end - begin ) / 2 //(the middle element)
while ( i != mid ) {    
   // ... do stuff
   increment i
}

while ( i != end ) {
   // ... do stuff
   // ... do other stuff
   increment i
}
Run Code Online (Sandbox Code Playgroud)

现在我甚至在SO上看到了一个关于如何以一种很好的方式写出-clause 的问题if ......我很难过:有些东西不在这里.

我错了吗?如果是这样的话,那么在编码时你会注意到特殊情况下的循环体是多么的好?

Tre*_*reb 20

我不认为这个问题应该由一个原则来回答(例如"在循环中,平等地对待每个元素").相反,您可以查看两个因素来评估实现是好还是坏:

  1. 运行时有效性 - 编译后的代码运行速度快,还是以不同的方式更快地运行?
  2. 代码可维护性 - 对于其他开发人员来说,了解这里发生的事情是否容易?

如果它更快并且通过在一个循环中执行所有操作来使代码更具可读性,那么就这样做.如果它更慢,更不易读,那就换一种方式吧.

如果它更快,更不易读,或更慢但更易读,请找出在特定情况下更重要的因素,然后决定如何循环(或不循环).


Mat*_*tW. 10

我知道当人们试图将数组元素连接成逗号分隔的字符串时,我已经看到过这种情况:

for(i=0;i<elements.size;i++) {
   if (i>0) {
     string += ','
   }
   string += elements[i]
}
Run Code Online (Sandbox Code Playgroud)

你要么在那里有if子句,要么必须在最后再次复制字符串+ = line.

在这种情况下,明显的解决方案是

string = elements.join(',')
Run Code Online (Sandbox Code Playgroud)

但是join方法在内部执行相同的循环.并不总是有办法做你想做的事.


aku*_*aku 6

@xtofl,

我同意你的担忧.

百万次我遇到类似的问题.

开发人员为第一个或最后一个元素添加特殊处理.

在大多数情况下,值得从startIdx + 1endIdx - 1元素循环,或者甚至将一个长循环分成多个较短的循环.

在极少数情况下,不可能分割循环.

在我看来,只要有可能,就应该在循环之外处理不常见的事情.


Mic*_*own 5

我开始意识到,当我把特殊情况放入for循环中时,我通常会因为自己的利益而过于聪明.


Swa*_*and 5

在你发布的最后一个片段中,你正在重复//代码的代码.

当你在一组不同的索引上有完全不同的操作集时,保留2个循环是有意义的.

i = begin
mid = ( end - begin ) / 2 //(the middle element)
while ( i != mid ) {    
   // ... do stuff
   increment i
}

while ( i != end ) {
   // ... do other stuff
   increment i
}
Run Code Online (Sandbox Code Playgroud)

情况并非如此,您仍然希望保留一个循环.但事实仍然是你仍然保存(结束 - 开始)/ 2次比较.因此,它归结为您是希望代码看起来整洁还是想要节省一些CPU周期.打电话是你的.


Jon*_*son 5

我想你已经完全搞定了。大多数人陷入了在循环中包含条件分支的陷阱,当他们可以在外部执行它们时:这只是更快

例如:

if(items == null)
    return null;

StringBuilder result = new StringBuilder();
if(items.Length != 0)
{
    result.Append(items[0]); // Special case outside loop.
    for(int i = 1; i < items.Length; i++) // Note: we start at element one.
    {
        result.Append(";");
        result.Append(items[i]);
    }
}
return result.ToString();
Run Code Online (Sandbox Code Playgroud)

你描述的中间情况只是简单的令人讨厌。想象一下,如果该代码增长并需要重构为不同的方法。

除非您正在解析 XML,否则 <grin> 循环应尽可能保持简单和简洁。