【问题标题】:Looping best practices循环最佳实践
【发布时间】:2009-03-26 14:08:30
【问题描述】:

我有一个非常大的循环,可以循环 1000 行。如果找到魔法值 1,我将退出循环。如果没有找到魔法值 1 但找到了魔法值 2,则循环需要跳到开头。现在我正在使用一个开关,一些ifs和一个goto。我读过 goto 不是最好的方法。有没有更好的方法来完成这项工作?

【问题讨论】:

  • 请贴一些代码。它将帮助我们对其进行可视化和改进。
  • “跳到开头”是指在下一次迭代时重新开始循环,还是在第一次迭代时重新开始循环?
  • 如果您提供一些示例代码以及您真正想要实现的目标,这可能会有所帮助。你所描述的听起来像是一些非常糟糕的编码......
  • 行中的数据是否不断变化?如果找到值 2,我不明白你为什么要从头开始......
  • 如果你在打到2的时候循环回到开头,会不会导致无限循环?

标签: c# break continue


【解决方案1】:

要退出循环,您可以使用break 语句,要进入下一条记录,您可以使用continue 语句。

for(int i = 0; i < 1000; i++)
{
    if(magicValue1)
       break;
    if(magicValue2)
       continue;
}

我不容忍使用 GOTO 语句,我只是指出一个可能的用例

您可以使用 goto 跳转语句来启动/退出循环,但是除非您使用 嵌套循环,否则我会远离此选项。我认为 goto 语句在优化、干净退出等方面仍有其用途。但总的来说,最好相当谨慎使用它。

for(int i = 0; i < 100; i++)
{ 
  start:

  for(int i = 0; i < 10; i++)
  {
     if(magicValue1)
       goto end;
    if(magicValue2)
       goto start;
  }
}
end : 

【讨论】:

  • -1,goto 可能有它的用途,但这不是其中之一。在所有这种情况下,您都可以将嵌套循环重构为单独的方法并使用 return。
  • 第 1 点和第 2 点不对。对于 1,您可以将其包装在 try {} finally {} 块中,它看起来会更好,请参阅我对数字 2 的其他评论。
  • +1 能够解释一个概念而不提倡在所有情况下使用它。
  • @Samuel - goto 并不是每个人都知道的可怕的大怪物。它非常快,并且在正确使用时可以非常易读。我不提倡使用它,并且在我的整个编程生涯中只使用过一次。
  • 在这种特殊情况下,goto 并没有什么坏处——它与breakcontinue 没有根本的不同(后者只是碰巧使用了隐式标签)。如果你反对在这种情况下使用goto,你也应该反对breakcontinue
【解决方案2】:

这个怎么样:

for(int i = 0; i < 1000; i++) {
    if(values[i] == MAGIC_VALUE_1) {
        break;
    } else if(values[i] == MAGIC_VALUE_2) {
        i = 0;
    }
}

如果“跳到开头”是指“跳过这条记录并处理下一条”,请将i = 0 替换为continue

【讨论】:

  • 只是用一个 While 循环来代替
  • 唯一的问题(这可能是原作者的问题的措辞有问题),一旦你达到魔法值2,它会重新开始,直到它达到魔法值2,然后它会重新开始,无限。根据他的说法,您的代码绝对正确
  • 我实际上建议为此使用 while 循环,因为大多数人希望 for 循环中的第三条语句是唯一修改索引变量的东西。 while 循环不会引起这种偏见,因此更容易理解。
  • @TheTXI:也许他正在修改数据,所以在下一次运行时值不同。根据问题,这个答案是有效的。
  • @TheTXI:我认为 OP 必须修改循环中的值。否则,正如您和 DaveK 所指出的那样,这显然会导致无限循环。
【解决方案3】:

没有breakwhile 变体:

bool continue = true; int i = 0;
while (i < 1000 && continue){
    if(values[i] == MAGIC_VALUE_1) {
        continue=false;
    } else if(values[i] == MAGIC_VALUE_2) {
        i = 0;
    }
    i++;
}

【讨论】:

    【解决方案4】:

    我还不能评论(1个代表点)

    但这不是更好吗:

    for (int i = 0; i < 1000; i++)
    {
        if (magicValue1)
        {
           break;
        }
        else if (magicValue2)
        {
           dosomething();
           i=0;
        }
    }
    

    我不确定“重新开始搜索”是什么意思。

    【讨论】:

    • 原始帖子标记为 C#,因此您需要“else”而不是“Else”。而且您的 if 语句需要将 magicValues to 进行比较,例如: if(values[i]==magicValue1)
    【解决方案5】:

    我将 #2 案例表示您不想在 #2 案例中执行(即跳过)循环体,而不是将循环重置为 0。(请参阅代码 cmets if I'倒过来了。)

    这个建议可能会引起争议,因为 for 循环中不太常规的条件可以说在自我记录规模上很低,但如果这不打扰你,一种简洁的方式来写我认为你的内容想要的是:

            for (int i= 0; i<values.Length && values[i]!= MAGIC_1; i++)
            {
                if (values[i] == MAGIC_2)
                {
                    // Don't do the loop body for this case but continue on looping
                    continue;
                    // If you want to reset the loop to zero instead of skip the 2 case,
                    // comment-out the continue; and un-comment the line below:
                    // i=0;
                }
                // Do long loop body here
            }
    

    【讨论】:

      【解决方案6】:

      请注意,如果您在 MagicValue 为 2 时将计数器设置回 0,并且您的代码永远不会更改值,那么您可能会陷入无限循环。

      【讨论】:

        【解决方案7】:

        更复杂的可能是:

        我们定义了 2 种扩展方法。

        public static class Extensions
        {
           public static bool isMagic_1(this int i)
           {
                 return i == 1;
           }
        
           public static bool isMagic_2(this int i)
           {
                 return i == 2;
           }
        }
        

        现在你可以这样做了:

          for(int i = 0; i < 1000; i++)
          {
             if(i.isMagic_1())
               break;
             if(i.isMagic_2())
               continue;
          }
        

        希望这会有所帮助!

        【讨论】:

        • 返回true还是false不是更好
        • 实际上是返回真或假。
        猜你喜欢
        • 1970-01-01
        • 2011-06-11
        • 2018-09-23
        • 2012-09-20
        • 2019-03-16
        • 1970-01-01
        • 2011-02-23
        • 1970-01-01
        相关资源
        最近更新 更多