【问题标题】:Clean way to break outer for loop from inner for loop从内部 for 循环中断外部 for 循环的干净方法
【发布时间】:2012-12-07 04:00:41
【问题描述】:

假设您有一个双重嵌套的 for,例如当您试图查看一个未排序数组中的项目是否在另一个未排序数组中时。例如,假设您有 2 个列表 candidatescorruptPeople,您将通过 candidates 并跳过 corruptPeople 中列出的列表。

for( int i = 0 ; i < lenCandidates ; i++ )
{
    // veto candidates[i] if candidates[i] is in corruptPeople at all
    for( int j = 0 ; j < lenCorruptPeople ; j++ )
        if( candidates[i] == corruptPeople[j] )
             break_this_loop_and_then_continue_outer_loop ;

    // initiate the eligible candidates
    initiate( candidates[i] ) ;
}

【问题讨论】:

  • 这些回答你的问题吗?

标签: c nested-loops


【解决方案1】:

一种方法(我愿意接受同行评审!)是使用goto

for( int i = 0 ; i < lenCandidates ; i++ )
{
    // veto candidates[i] if candidates[i] is in corruptPeople at all
    for( int j = 0 ; j < lenCorruptPeople ; j++ )
        if( candidates[i] == corruptPeople[j] )
             goto END_FOR ;

    // initiate the eligible candidates
    initiate( candidates[i] ) ;

    END_FOR:
    ; // seem to need an empty statement to make it compile
}

我很好奇其他人对在这种情况下使用goto 有什么看法。与goto 的教条式分歧意味着您将有一个教条式的结构化编程应用程序。当我尝试它时看起来很糟糕。

【讨论】:

  • 我不认为使用 goto 可以被认为是一个干净的解决方案——即使最终它是必要的。
  • 就个人而言,这是我更喜欢goto的少数情况之一。尽管它受到诽谤,也可能被滥用,但我发现在这种情况下它比其他解决方案更简单。
  • 它可能不干净,但不幸的是,C 没有任何东西像 Python 的 for ... else 构造那样好。
  • 您需要一个空语句来使其编译的原因是; 是一个语句,但一个空的标记序列不是。因此END_FOR:; 是带标签的语句,而END_FOR: 不是。
  • 一些关于;需求的信息... stackoverflow.com/questions/8384388/…
【解决方案2】:

使用附加变量比使用 goto 更好:

for( int i = 0 ; i < lenCandidates ; i++ )
{
    // veto candidates[i] if candidates[i] is in corruptPeople at all
    int corrupt = 0;
    for( int j = 0 ; j < lenCorruptPeople ; j++ )
        if( candidates[i] == corruptPeople[j] )
        {
            corrupt = 1;
            break;
        }

    // initiate the eligible candidates
    if (!corrupt) initiate( candidates[i] ) ;
}

【讨论】:

  • 对不起,我删除了我的答案..没有看到这个..我的也是一样
  • 这是最干净的方式.. 也很容易理解
  • 我不明白为什么要创建一个额外的变量并添加额外的代码——包括一个应该是多余的检查,因为我们知道它在 every 代码路径中的值——是“比诉诸goto 好得多。
【解决方案3】:

下面的代码怎么样?我错过了什么吗?

for( int i = 0 ; i < lenCandidates ; i++ )
{
    // veto candidates[i] if candidates[i] is in corruptPeople at all
    int j;
    for( j = 0 ; j < lenCorruptPeople ; j++ )
    {
        if( candidates[i] == corruptPeople[j] )
          break;
    }

    //j will be equal to lenCorruptPeople only when candidate is not in corrupt list   
    if(j==lenCorruptPeople)
    {
        initiate( candidates[i] ) ;
    }

}

【讨论】:

  • 是的,j 超出了if(j!=lenCorruptPeople) 的范围
  • @Krishnabhadra,稍作改动。现在,会好吗?
  • 好的,现在它是正确的。但我还是更喜欢特洛伊的回答,它更容易理解和指导。
  • 我同意。肯定使用 break over goto。
  • goto 允许我们将变量保持在循环的本地,同时不重复对j 的循环结束检查。这个break的方法是不是更清楚了?只要goto仅限于这种情况,我看不出有什么问题。
【解决方案4】:

将内部循环移动到另一个函数通常会有所帮助:

typedef int Person; // or whatever it is.

Person *findPerson(Person *first, Person *last, Person val)
{
    while (first != last)
    {
        if (val == *first) return first;
        ++first;
    }
    return 0;
}

...

for( int i = 0 ; i < lenCandidates ; i++ )
{
    // veto candidates[i] if candidates[i] is in corruptPeople at all
    if (!findPerson(corruptPeople, corruptPeople+lenCorruptPeople, candidates[i]))
    {
        // initiate the eligible candidates
        initiate( candidates[i] ) ;
    }
}

【讨论】:

  • 如果每次遇到这种情况都必须定义一个新函数,我想我会发疯的。
  • @JoshuaGreen:幸运的是,您不必每次都这样做,但它通常会有所帮助。在这种情况下,“查找”是一个简单的抽象,甚至可以重用,所以我认为它是一个相当不错的候选者。如果你不喜欢做一件事的短函数,那么findPerson 是一场噩梦;-p
猜你喜欢
  • 2013-06-07
  • 2020-04-04
  • 2015-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-28
相关资源
最近更新 更多