【问题标题】:How can I break out of two nested for loops in Objective-C?如何打破 Objective-C 中的两个嵌套 for 循环?
【发布时间】:2010-10-26 04:16:25
【问题描述】:

我有两个这样嵌套的 for 循环:

for(...) {
    for(...) {

    }
}

我知道有一个break 声明。但是我很困惑它是打破两个循环还是仅仅打破它被调用的那个?一旦我发现迭代更多次没有意义,我就需要打破这两个。

【问题讨论】:

    标签: c objective-c loops


    【解决方案1】:

    只是为了笑,如何将这个真/假检查更改为方法并使用return 语句:

    - (bool) checkTrueFalse: parameters{
    
       for ( ...) {
          for ( ... ) {
    
             if (...) {
                return true;
             }
    
          }
       }
       return false;
    }
    

    【讨论】:

      【解决方案2】:

      和最后一个完全一样,一般是这样的:

      for(i=0;i<a;i++){  
       for(j=0;j<a;j++){
        if(Something_goes_wrong){
         i=a;
         break;
         }
       }
      }
      

      【讨论】:

        【解决方案3】:

        另一种解决方案是在函数中分解出第二个循环:

        int i;
        
        for(i=0; i<10 ; i++){
            if !innerLoop(i) {
                break;
            }
        }
        
        bool innerLoop(int i)
            int j;
            for(j=0;j< 10; j++){
                doSomthing(i,j);
                if(endcondtion){
                    return false;
                }
            }
        }
        

        【讨论】:

          【解决方案4】:

          除了已经提到的标志变量或转到您可以throw Objective-C 异常:

          @try {
            for() {
              for() {
                 @throw ...
              }
            }
          }
          @catch{
            ...
          }
          

          【讨论】:

          • 哇,正如我正要修改我的答案以指出人们将如何建议每一个复杂的解决方案,除了使用异常进行流控制以避免转到...
          • @Ori Pessach Well 例外是 goto 的现代 OO 版本 ;-)
          • 他们确实很好地清理了堆栈,至少。
          • 根据我的经验,异常非常慢,不应该用于处理执行流程。
          • 对 ObjC 中的异常做一些研究。在 Apple 文档中,他们特别指出对性能的影响很大,他们说:“Cocoa 框架通常不是异常安全的。一般模式是异常只为程序员错误保留,捕获此类异常的程序应该很快退出。”
          【解决方案5】:

          如果使用 goto 可以简化代码,那就合适了。

          for (;;) 
          {
              for (;;) 
              {
                  break; /* breaks inner loop */
              } 
              for (;;) 
              {
                  goto outer; /* breaks outer loop */
              }
          } 
          outer:;
          

          【讨论】:

          • 要对此进行扩展,for (;;) {for (;;) {break; /* breaks inner loop */} for (;;) {goto outer; /* breaks outer loop */}} outer:;
          • (;;) 看起来像一张小脸。
          【解决方案6】:

          可能最简单的方法是使用“标志”变量

          for(i=0; i<10 && (done==false); i++)
            for(j=0;j< 10; j++){
               ..
               ..
               if(...){done=true; break;}
            }
          

          【讨论】:

          • @Jonny 这些在 Obj-C 中被称为 fast-enumeration 循环
          【解决方案7】:

          break 跳出一个循环,但您可以在外循环中添加一个检查,当内循环中断时。

          bool dobreak = false;
          for ( ..; !dobreak && ..; .. ) {
             for ( ... ) {
                if (...) {
                   dobreak = true;
                   break;
                }
             }
          }
          

          【讨论】:

          • 恕我直言,使用 goto 更干净。
          • !dobreak 放错地方了;它应该进入条件(for的第二部分)而不是增量步骤(for的第三部分);我也会使用!dobreak &amp;&amp; ..,以便在中断时不需要评估其他条件。我同意 sigjuice:goto 在正确使用时并不邪恶,这是goto 确实 编写更好的代码的情况。
          • 这仍然会执行可能在内循环之后的外循环中的代码
          • @Martijn - 这可以通过将break 替换为continue 语句来解决。不过,这只是更不明显的事情需要担心。
          【解决方案8】:

          其他人已经提到如何设置标志或使用goto,但我建议重构您的代码,以便将内部循环变成一个单独的方法。然后该方法可以返回一些标志来指示外部循环应该break。如果您适当地命名您的方法,这将更具可读性。

          for (int i = 0; i < 10; i++) {
             if (timeToStop(i)) break;
          }
          
          -(bool) timeToStop: (int) i {
              for (int j = 0; j < 10; j++) {
                  if (somethingBadHappens) return true;
              }
          
              return false;
          }
          

          伪代码,未经测试,但你明白了。

          【讨论】:

            【解决方案9】:

            break 语句只会让你跳出最里面的循环。如果您不希望在代码、内存和专用状态变量的性能方面增加开销,我建议将代码重构为自己的函数或方法,并使用return 摆脱所有循环:

            void do_lots_of_work(void)
            {
              int i, j;
            
              for(i=0; i<10 ; i++)
              {
                for(j=0;j< 10; j++)
                {
                 ..
                 ..
                 if(disaster_struck())
                  return; /* Gets us out of the loops, and the function too. */
                }
              }
            }
            

            【讨论】:

            • 如果循环中的函数调用能够像专用状态变量一样执行,我会感到非常惊讶,特别是如果您需要传递参数才能访问外部函数中的变量.也许如果编译器内联复制函数...
            • 在我看来,更糟糕的是失去了通过在一个地方阅读算法来理解算法的能力。所有这些都是为了避免 goto?
            • 我也遇到过这个中断/继续问题,有时想继续循环 2-3 级。恕我直言,最好的做法是将嵌套循环重构为一个方法,以便该方法可以返回是否继续父循环。
            • 如果用户只想退出循环而不退出函数怎么办?
            • 我认为这是最好的解决方案。发生的事情很明确,很容易控制,很容易调用,它不会分配和评估不必要的布尔值,也不会使用像goto 这样的危险旧做法。在任何实际使用中,性能问题也不应该引起注意。
            【解决方案10】:

            在中断前更改顶部循环的计数器

            for(i=0; i<10 ; i++)
              for(j=0;j< 10; j++){
                 ..
                 ..
                 i = 10; 
                 break;
              }
            

            【讨论】:

            • 我不太喜欢这个。风险在于有人在一处更改了退出条件,而忘记了另一处。
            • NSUInteger limit = 10; 然后:for(i=0; i&lt;limit; i++) { for(j=0; j&lt;10; j++) { .. .. i = limit; break; } }
            【解决方案11】:

            break 语句跳出最里面的循环。需要额外的 test 和 break 语句来跳出外循环。

            【讨论】:

              【解决方案12】:

              break 语句只会跳出作用域内的循环,也就是父循环。如果你也想跳出第二个循环,你可以使用两个循环范围内的布尔变量

              bool isTerminated = false;
              
              for (...)
              {
                  if (!isTerminated)
                  {
                      for(...)
                      {
                          ...
              
                          isTerminated = true;
                          break;
                      }
                  }
                  else
                  {
                      break;
                  }
              }
              

              【讨论】:

                【解决方案13】:

                如果从一组嵌套循环中执行中断,则仅终止执行中断的最内层循环。 (就像标准 C 一样)

                【讨论】:

                  猜你喜欢
                  • 2011-10-22
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-03-30
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-11-30
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多