打破 JavaScript 中嵌套循环的最佳方法是啥?

Posted

技术标签:

【中文标题】打破 JavaScript 中嵌套循环的最佳方法是啥?【英文标题】:What's the best way to break from nested loops in JavaScript?打破 JavaScript 中嵌套循环的最佳方法是什么? 【发布时间】:2010-09-16 00:55:29 【问题描述】:

javascript 中打破嵌套循环的最佳方法是什么?

//Write the links to the page.
for (var x = 0; x < Args.length; x++)

   for (var Heading in Navigation.Headings)
   
      for (var Item in Navigation.Headings[Heading])
      
         if (Args[x] == Navigation.Headings[Heading][Item].Name)
         
            document.write("<a href=\"" 
               + Navigation.Headings[Heading][Item].URL + "\">" 
               + Navigation.Headings[Heading][Item].Name + "</a> : ");
            break; // <---HERE, I need to break out of two loops.
         
      
   

【问题讨论】:

这里是打破循环和代码块的好例子:marcin-chwedczuk.github.io/… 【参考方案1】:

分配比较条件中的值

function test()
    for(var i=0;i<10;i++)
    
            for(var j=0;j<10;j++)
            
                    if(somecondition)
                    
                            //code to Break out of both loops here
                            i=10;
                            j=10;
                    
                    
            
    

    //Continue from here

【讨论】:

【参考方案2】:

上面有很多优秀的解决方案。 IMO,如果您的休息条件是例外, 你可以使用try-catch:

try  
    for (var i in set1) 
        for (var j in set2) 
            for (var k in set3) 
                throw error;
            
        
    
catch (error) 


【讨论】:

【参考方案3】:

就像 Perl,

loop1:
    for (var i in set1) 
loop2:
        for (var j in set2) 
loop3:
            for (var k in set3) 
                break loop2;  // breaks out of loop3 and loop2
            
        
    

如 EMCA-262 第 12.12 节中所定义。 [MDN Docs]

与 C 不同,这些标签只能用于 continuebreak,因为 Javascript 没有 goto

【讨论】:

WTF 为什么我在 3 年的 JavaScript 中没有看到它被用于某个地方:/.. MDN 说“避免使用标签”纯粹是出于可读性的原因。为什么它不“可读”?因为没有人使用它们,当然。但是他们为什么不使用它们呢? ... @Web_Designer 我相信你的评论已经过时了。 MDN 文档中没有任何地方说“避免使用标签”。请考虑修改或删除您的评论。 @SeantheBean 完成。这似乎是更直接的答案,并且不会被滥用,因为它仅适用于 continuebreak @JérémyPouyet - 你反对投票的逻辑是愚蠢和没有根据的。它完美地回答了OP的问题。该问题与您对易读性的看法无关。请重新考虑您协助社区的方式。【参考方案4】:

很简单:

var a = [1, 2, 3];
var b = [4, 5, 6];
var breakCheck1 = false;

for (var i in a) 
    for (var j in b) 
        breakCheck1 = true;
        break;
    
    if (breakCheck1) break;

【讨论】:

我同意这实际上是最好的,函数一个不能扩展,将所有的 for 循环包装在 if 也不能扩展 ie 使得它难以阅读和调试......这个很棒.您可以只声明 vars loop1、loop2、loop3,并在最后添加小语句。另外要打破多个循环,您需要执行loop1=loop2=false; 之类的操作 我已经使用了这种安排并且它可以工作,而不会因为无用的功能而复杂化。我只是在搜索了一些东西来看看js是否有break 2;就像在php中一样。【参考方案5】:

嗯,10 岁的聚会你好?

为什么不在你的 for 中设置一些条件?

var condition = true
for (var i = 0 ; i < Args.length && condition ; i++) 
    for (var j = 0 ; j < Args[i].length && condition ; j++) 
        if (Args[i].obj[j] == "[condition]") 
            condition = false
        
    

这样你想停就停

在我的例子中,使用 Typescript,我们可以使用 some() 来遍历数组并在满足条件时停止 所以我的代码变成了这样:

Args.some((listObj) => 
    return listObj.some((obj) => 
        return !(obj == "[condition]")
    )
)

这样,满足条件后循环立即停止

提醒:此代码在 TypeScript 中运行

【讨论】:

【参考方案6】:

以下是打破 JavaScript 中嵌套循环的五种方法:

1) 将父循环设置到末尾

for (i = 0; i < 5; i++)

    for (j = 0; j < 5; j++)
    
        if (j === 2)
        
            i = 5;
            break;
        
    

2) 使用标签

exit_loops:
for (i = 0; i < 5; i++)

    for (j = 0; j < 5; j++)
    
        if (j === 2)
            break exit_loops;
    

3) 使用变量

var exit_loops = false;
for (i = 0; i < 5; i++)

    for (j = 0; j < 5; j++)
    
        if (j === 2)
        
            exit_loops = true;
            break;
        
    
    if (exit_loops)
        break;

4) 使用自执行功能

(function()

    for (i = 0; i < 5; i++)
    
        for (j = 0; j < 5; j++)
        
             if (j === 2)
                 return;
        
    
)();

5) 使用正则函数

function nested_loops()

    for (i = 0; i < 5; i++)
    
        for (j = 0; j < 5; j++)
        
             if (j === 2)
                 return;
        
    

nested_loops();

【讨论】:

@Wyck 我不能同意!遗憾的是,javascript 不像我们在 PHP 中那样简单地具有 break 2; 语法。没有循环标签,没有函数,没有 if-else 检查,没有循环变量的回火/爆破——只有干净的语法! 示例 4 很不错 @JayDadhania 抱歉,您的“干净”和“简单”语法给我们的软件带来了错误。显式优于隐式。我想自己命名我的标签。 @EkremDinçel break 2; 这样的语法在 JS 中还不存在,那它怎么会引入错误呢?您想手动标记循环吗?当然,继续 - 我从来没有说过你不应该。另外,我绝不建议使用3,2,1手动标记 JS 循环 - 到目前为止,JS 不允许仅使用数字手动标记循环。我只是希望这样的东西是隐含的。此外,这样的声明一直是一些非常流行的语言(如 PHP)的核心部分,我还没有遇到(m)任何 “想要手动标记 PHP 循环的帖子,因为 break 2; 很难重新-结构”。 @JayDadhania 它肯定不会在 JS 中引入错误,它不存在。但如果它存在的话,我想我在上面的评论中解释得有点错误。你想要的隐含是一个问题,如果它存在于javascript中,无论你是否建议,人们都会使用它。您以 PHP 作为此语法的示例,我认为您还应该注意到 PHP 的糟糕历史。我听说他们现在正在修复一些东西,但它是一种语言,很长一段时间以来,在用它编写的应用程序中都有如此多的意大利面条代码,这是有原因的。【参考方案7】:

swilliams 之前已经提到过,但下面有一个示例(Javascript):

// Function wrapping inner for loop
function CriteriaMatch(record, criteria) 
  for (var k in criteria) 
    if (!(k in record))
      return false;

    if (record[k] != criteria[k])
      return false;
  

  return true;


// Outer for loop implementing continue if inner for loop returns false
var result = [];

for (var i = 0; i < _table.length; i++) 
  var r = _table[i];

  if (!CriteriaMatch(r[i], criteria))
    continue;

  result.add(r);

【讨论】:

【参考方案8】:

如何将循环推到极限

    for(var a=0; a<data_a.length; a++)
       for(var b=0; b<data_b.length; b++)
           for(var c=0; c<data_c.length; c++)
              for(var d=0; d<data_d.length; d++)
                 a =  data_a.length;
                 b =  data_b.length;
                 c =  data_b.length;
                 d =  data_d.length;
            
         
       
     

【讨论】:

我认为Drakes answer的逻辑相同,更简洁明了。 绝对精彩!【参考方案9】:

最好的方法是- 1)对第一个和第二个循环中使用的两个数组进行排序。 2) 如果项目匹配,则中断内部循环并保持索引值。 3)当开始下一次迭代时,以保持索引值开始内循环。

【讨论】:

【参考方案10】:

我想我会展示一种函数式编程方法。你可以打破嵌套的 Array.prototype.some() 和/或 Array.prototype.every() 函数,就像我的解决方案一样。这种方法的另一个好处是Object.keys() 仅枚举对象自身的可枚举属性,而"a for-in loop enumerates properties in the prototype chain as well"。

接近OP的解决方案:

    Args.forEach(function (arg) 
        // This guard is not necessary,
        // since writing an empty string to document would not change it.
        if (!getAnchorTag(arg))
            return;

        document.write(getAnchorTag(arg));
    );

    function getAnchorTag (name) 
        var res = '';

        Object.keys(Navigation.Headings).some(function (Heading) 
            return Object.keys(Navigation.Headings[Heading]).some(function (Item) 
                if (name == Navigation.Headings[Heading][Item].Name) 
                    res = ("<a href=\""
                                 + Navigation.Headings[Heading][Item].URL + "\">"
                                 + Navigation.Headings[Heading][Item].Name + "</a> : ");
                    return true;
                
            );
        );

        return res;
    

减少标题/项目迭代的解决方案:

    var remainingArgs = Args.slice(0);

    Object.keys(Navigation.Headings).some(function (Heading) 
        return Object.keys(Navigation.Headings[Heading]).some(function (Item) 
            var i = remainingArgs.indexOf(Navigation.Headings[Heading][Item].Name);

            if (i === -1)
                return;

            document.write("<a href=\""
                                         + Navigation.Headings[Heading][Item].URL + "\">"
                                         + Navigation.Headings[Heading][Item].Name + "</a> : ");
            remainingArgs.splice(i, 1);

            if (remainingArgs.length === 0)
                return true;
            
        );
    );

【讨论】:

【参考方案11】:

如果您使用 Coffeescript,有一个方便的“do”关键字,可以更轻松地定义和立即执行匿名函数:

do ->
  for a in first_loop
    for b in second_loop
      if condition(...)
        return

...所以你可以简单地使用“return”来退出循环。

【讨论】:

这不一样。我原来的例子有三个 for 循环而不是两个。【参考方案12】:

完全不使用中断,不使用中止标志,也不使用额外的条件检查怎么样。这个版本只是在满足条件时爆破循环变量(使它们成为Number.MAX_VALUE)并强制所有循环优雅地终止。

// No breaks needed
for (var i = 0; i < 10; i++) 
  for (var j = 0; j < 10; j++) 
    if (condition) 
      console.log("condition met");
      i = j = Number.MAX_VALUE; // Blast the loop variables
    
  

对于递减类型的嵌套循环有一个类似的答案,但这适用于递增类型的嵌套循环,而无需考虑简单循环的每个循环的终止值。

另一个例子:

// No breaks needed
for (var i = 0; i < 89; i++) 
  for (var j = 0; j < 1002; j++) 
    for (var k = 0; k < 16; k++) 
      for (var l = 0; l < 2382; l++) 
        if (condition) 
          console.log("condition met");
          i = j = k = l = Number.MAX_VALUE; // Blast the loop variables
        
      
    
  

【讨论】:

【参考方案13】:

将其包装在一个函数中,然后只需 return

【讨论】:

我选择接受这个答案,因为它很简单并且可以以优雅的方式实现。我绝对讨厌 GOTO 并认为它们是不好的做法(可以打开),Ephemient 太接近了。 ;o) IMO,只要不破坏结构,GOTO 就可以。但对每个人来说都是他们自己的! for 循环上的标签与 GOTO 没有绝对没有共同之处,除了它们的语法。它们只是从外部循环中打破的问题。打破最里面的循环没有任何问题,是吗?那么为什么你在打破外循环时遇到问题呢? 请考虑接受其他答案。如果不是因为 Andrew Hedges 的评论(顺便说一句,谢谢),我会想:啊,所以 javascript 没有那个功能。我敢打赌,社区中的许多人可能会忽略评论并认为是一样的。 为什么 Stack Overflow 没有让社区覆盖明显错误的选择答案的功能? ://【参考方案14】:

我意识到这是一个非常古老的话题,但由于我的标准方法还没有出现,我想我把它发布给未来的谷歌人。

var a, b, abort = false;
for (a = 0; a < 10 && !abort; a++) 
    for (b = 0; b < 10 && !abort; b++) 
        if (condition) 
            doSomeThing();
            abort = true;
        
    

【讨论】:

如果在嵌套循环的第一次迭代中 condition 的计算结果为 true,您仍然会运行其余 10 次迭代,每次都检查 abort 值。这不是 10 次迭代的性能问题,但它会是 10,000 次。 不,它从两个循环中退出。这是演示fiddle。不管你设置什么条件,满足后退出。 优化就是加个break;设置 abort = true 后;并从最终循环中删除 !abort 条件检查。 我喜欢这个,但我认为在一般意义上你会做很多不必要的处理——也就是说,对于每个迭代器 evalueate abort 和表达式的每次迭代。在简单的场景中可能没问题,但对于具有无数次迭代的巨大循环可能是个问题 +1 表示一种新颖的方法!但是,这对 for(var a in b)...for(var a of b)... 样式的循环没有帮助。【参考方案15】:
XXX.Validation = function() 
    var ok = false;
loop:
    do 
        for (...) 
            while (...) 
                if (...) 
                    break loop; // Exist the outermost do-while loop
                
                if (...) 
                    continue; // skips current iteration in the while loop
                
            
        
        if (...) 
            break loop;
        
        if (...) 
            break loop;
        
        if (...) 
            break loop;
        
        if (...) 
            break loop;
        
        ok = true;
        break;
     while(true);
    CleanupAndCallbackBeforeReturning(ok);
    return ok;
;

【讨论】:

这看起来比原来的更混乱。 投了赞成票,因为一段时间更适合这种情况(在大多数情况下)。【参考方案16】:

我参加聚会有点晚了,但以下是一种与语言无关的方法,它不使用 GOTO/标签或函数包装:

for (var x = Set1.length; x > 0; x--)

   for (var y = Set2.length; y > 0; y--)
   
      for (var z = Set3.length; z > 0; z--)
      
          z = y = -1; // terminates second loop
          // z = y = x = -1; // terminate first loop
      
   

从好的方面来说,它会自然流动,这应该会取悦非 GOTO 人群。不利的一面是,内部循环需要在终止之前完成当前迭代,因此它可能不适用于某些场景。

【讨论】:

左大括号不应该换行,因为js实现可能会在前一行的末尾插入一个冒号。 @Evgeny:虽然一些 JavaScript 样式指南要求左大括号放在同一行,但将它放在新行上并没有错,并且解释器不存在歧义插入分号的危险. ASI 的行为已明确定义,此处不适用。 请务必注释掉这种方法。这里发生了什么并不是很明显。 不错且简单的答案。这应该被视为答案,因为它不会占用 CPU 密集型循环(这是使用函数的问题),或者它不使用通常不可读或不应该像某些人所说的那样使用的标签。 :) 我可能遗漏了一些东西,但是为了解决内部循环必须完成该迭代的问题,您可以在设置 z 和 y 后立即输入 breakcontinue 吗?我确实喜欢使用for 循环的条件来退出的想法。以自己的方式优雅。【参考方案17】:
var str = "";
for (var x = 0; x < 3; x++) 
    (function()   // here's an anonymous function
        for (var y = 0; y < 3; y++) 
            for (var z = 0; z < 3; z++) 
                // you have access to 'x' because of closures
                str += "x=" + x + "  y=" + y + "  z=" + z + "<br />";
                if (x == z && z == 2) 
                    return;
                
            
        
    )();  // here, you execute your anonymous function

怎么样? :)

【讨论】:

我认为这就是 swilliams 的目的 如果循环很大,这会增加显着的运行时成本 - 必须由 Javascript 解释器/编译器(或“compreter”)创建(并在某些时候由 GC 释放)函数的新执行上下文这些天,两者兼而有之)每次。 这实际上是非常危险的,因为可能会发生一些你可能没有预料到的奇怪事情。特别是,由于使用 var x 创建的闭包,如果循环中的任何逻辑在稍后的时间点引用 x(例如,它定义了一个稍后保存并执行的内部匿名函数),x 的值将是循环的 end 中的任何内容,而不是该函数在其期间定义的索引。 (续) 要解决这个问题,您需要将x 作为参数传递给您的匿名函数,以便它创建它的新副本,然后可以引用为关闭,因为从那时起它不会改变。总之,我推荐ehemient的回答。 同样,我认为可读性是完全废话。这比标签更模糊。标签只被视为不可读,因为没有人使用它们。

以上是关于打破 JavaScript 中嵌套循环的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

打破嵌套循环[重复]

如何打破 Objective-C 中的两个嵌套 for 循环?

开放式加速器 | Fortran 90:并行化嵌套 DO 循环的最佳方法是啥?

如何打破 Dart 中的嵌套循环

Python打破嵌套的for循环并重新启动while循环

如何打破 Java 中的嵌套循环?