代码之家  ›  专栏  ›  技术社区  ›  xtofl Adam Rosenfield

循环中的最后一个元素需要单独处理吗?

  •  18
  • xtofl Adam Rosenfield  · 技术社区  · 16 年前

    回顾时,我有时会遇到这样的循环:

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

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

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

    在我看来,这比写循环的意图要好:循环是因为对于每个元素都有一些共同的事情要做。使用这个结构,对于一些元素,您可以做一些不同的事情。因此,我得出结论,您需要为这些元素创建一个单独的循环:

    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
    }
    

    现在我甚至看到 question 关于如何写 if -以一种很好的方式…我很难过:这里有些东西不对劲。

    我错了吗?如果是这样,那么在编码时将循环体与您预先知道的特殊情况混淆在一起有什么好处呢?

    13 回复  |  直到 12 年前
        1
  •  5
  •   aku    16 年前

    @ XTFOL,

    我同意你的担心。

    我遇到过无数次类似的问题。

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

    在大多数情况下,只需循环 斯塔迪克斯+ 1 Endix—1 元素,甚至将一个长循环拆分为多个短循环。

    在非常罕见的情况下,不可能分割循环。

    在我看来 罕见的 只要可能,事情就应该在循环之外处理。

        2
  •  19
  •   Treb    16 年前

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

    1. 运行时有效性-编译后的代码运行得快吗,或者用不同的方式更快?
    2. 代码可维护性——对于其他开发人员来说,理解这里发生的事情容易吗?

    如果在一个循环中做任何事情都能更快地读取代码,那么就这样做。如果速度较慢且可读性较低,请使用其他方法。

    如果它更快、更不可读,或者更慢但更可读,请找出在特定情况下哪些因素更重要,然后决定如何循环(或不循环)。

        3
  •  10
  •   Matthias Winkelmann    16 年前

    我知道,当人们试图将数组的元素连接成逗号分隔的字符串时,我看到了这一点:

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

    您要么在其中包含if子句,要么必须在末尾再次复制string+=行。

    在这种情况下,最明显的解决办法是

    string = elements.join(',')
    

    但是join方法在内部执行相同的循环。也不总是有一种方法可以做你想做的事。

        4
  •  5
  •   Paolo    16 年前

    我开始意识到,当我把特殊情况放到for循环中时,我通常太聪明了,不适合我自己。

        5
  •  5
  •   Swanand    16 年前

    在您发布的最后一个片段中,您重复了//….的代码。做些事情。

    当您对一组不同的索引执行完全不同的操作时,保持两个循环是有意义的。

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

    如果不是这样,您仍然希望保持一个单循环。但是,事实仍然是您仍然保存(结束-开始)/2个比较数。因此,归根结底,您是希望代码看起来整洁,还是希望节省一些CPU周期。电话是你的。

        6
  •  3
  •   Jonathan C Dickinson    16 年前

    我想你已经完全明白了。大多数人都陷入了在循环中包含条件分支的陷阱,当他们可以在外部进行时:这很简单 更快 .

    例如:

    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();
    

    你所描述的中间情况很简单 肮脏的 . 想象一下,如果代码增长,需要重构成不同的方法。

    除非您正在分析XML,否则循环应尽可能简单和简洁。

        7
  •  2
  •   Scottm    16 年前

    我认为你是对的,循环是用来平等地处理所有元素的。不幸的是,有时会出现一些特殊的情况,这些情况应该通过if语句在循环构造内部处理。

    如果有很多特殊情况,您可能应该考虑想出一些方法来处理不同构造中的两组不同的元素。

        8
  •  2
  •   Angelin Nadar    12 年前

    我更喜欢简单地从循环中排除元素 在环外进行长矛状治疗

    例如:让我们考虑一下EOF的情况。

    i = begin
    while ( i != end -1 ) {    
       // ... do stuff for element from begn to second last element
       increment i
    }
    
    if(given_array(end -1) != ''){
       // do stuff for the EOF element in the array
    }
    
        9
  •  1
  •   Dark Shikari    16 年前

    当然,在一个可以拉出的回路中,特殊的套管是愚蠢的。不过,我也不会复制do-u的内容;我要么把它放在函数中,要么放在宏中,这样我就不会复制粘贴代码。

        10
  •  1
  •   1800 INFORMATION    16 年前

    我讨厌看到的另一件事是 for-case pattern :

    for (i=0; i<5; i++)
    {
      switch(i)
      {
        case 0:
          // something
          break;
        case 1:
          // something else
          break;
        // etc...
      }
    }
    

    我在真实代码中看到过这个。

        11
  •  1
  •   Simon    16 年前

    哪一个表现更好?

    如果项目数量很大,那么我总是循环一次,特别是如果您要执行 一些 对每个项目的操作。评估条件的成本可能比循环成本低两倍。

    哎呀,当然你不会循环两次…在这种情况下,最好使用两个回路。但是,我认为主要考虑的应该是性能。如果您可以通过简单地操作循环边界(一次)来划分工作,就不需要在循环中引发条件(n次)。

        12
  •  0
  •   John Ferguson    16 年前

    如果只执行一次,则应在循环外部执行特殊情况。

    但是,可能有一个索引或其他一些变量,由于作用域的存在,它们更容易保存在循环中。在循环控制结构中,将数据结构上的所有操作放在一起可能还有一个上下文原因,尽管我认为这本身就是一个薄弱的论点。

        13
  •  0
  •   Nrj    16 年前

    它只是根据需要和方便使用它。因此,没有提到要平等地对待元素,当然也没有损害到语言提供的特性。

    推荐文章