具有嵌套 forEach 和 for 循环的函数不会返回 false

Posted

技术标签:

【中文标题】具有嵌套 forEach 和 for 循环的函数不会返回 false【英文标题】:Function with nested forEach and for loop won't return false 【发布时间】:2020-07-16 22:30:49 【问题描述】:

我正在做一个algorithm challenge 来练习 JS。我有一个通过循环运行的程序,当满足条件时,函数应该返回 false。但是,当条件满足时,返回不起作用,函数总是以返回 true 结束。

const isDiagonalLeftWristband = (band) => 
  band.forEach((row, y) => 
    row.forEach((item, x) => 
      for(let i = 0; (i < band[y].length - x) && (i < band.length - y); i++)         
        if (band[y][x] !== band[y+i][x+i]) 
          console.log(false) //FALSE GETS OUTPUTTED MULTIPLE TIMES
          return false;
        
      
    )
  )
  return true;



const band3 = [
  ["A", "B", "C"],
  ["C", "Z", "B"],
  ["B", "C", "A"],
  ["A", "B", "C"]
];

console.log(isDiagonalLeftWristband(band3))

输出:

false //from console log
false //from console log
true //from function return statement

任何帮助将不胜感激!

【问题讨论】:

【参考方案1】:

return false 只会退出 (item, x) =&gt; 匿名函数,而不是像您期望的那样退出 isDiagonalLeftWristband()。在两个forEach 被执行后,isDiagonalLeftWristband() 将始终以return true 结束。您可以使用循环来避免这个问题。

const isDiagonalLeftWristband = (band) => 
  for (let [y, row] of band.entries()) 
    for (let [x, item] of row.entries()) 
      for(let i = 0; (i < band[y].length - x) && (i < band.length - y); i++)         
        if (band[y][x] !== band[y+i][x+i]) 
          console.log(false) //FALSE GETS OUTPUTTED MULTIPLE TIMES
          return false;
        
      
    
  
  return true;


const band3 = [
  ["A", "B", "C"],
  ["C", "Z", "B"],
  ["B", "C", "A"],
  ["A", "B", "C"]
];

console.log(isDiagonalLeftWristband(band3))

forEach 并非旨在提前终止。它总是会遍历所有元素。 (它的名字:))。来自 MDN 文档:

没有其他方法可以停止或中断 forEach() 循环 抛出异常。如果你需要这样的行为,forEach() 方法 是错误的工具。

可以通过以下方式提前终止:

A simple for loop
A for...of / for...in loops
Array.prototype.every()
Array.prototype.some()
Array.prototype.find()
Array.prototype.findIndex()

数组方法:every()、some()、find() 和 findIndex() 测试数组 带有返回真值的谓词的元素以确定是否 需要进一步迭代。

您可以改为使用建议的函数之一,该函数旨在使用谓词测试数组的元素。 every() 测试数组的所有元素是否都通过了一些测试;这至少在语义上是您所需要的。

const isDiagonalLeftWristband = (band) => 
  return band.every((row, y) => 
    return row.every((item, x) => 
      for(let i = 0; (i < band[y].length - x) && (i < band.length - y); i++)         
        if (band[y][x] !== band[y+i][x+i]) 
          return false;
        
      
      return true;    
     );
  );


const band3 = [
  ["A", "B", "C"],
  ["C", "B", "B"],
  ["B", "C", "A"],
  ["A", "B", "C"]
];

console.log(isDiagonalLeftWristband(band3))

【讨论】:

这已经解决了我的问题,但是为了学习,有没有办法让函数与forEach一起工作? Naoufal 的答案是一个可能的解决方案,但就像他指出的那样,他的解决方案在找到第一个错误后不会退出。 @NicholasNewman 我已经编辑了我的答案来回答你的问题。简而言之,没有明智的方法可以提前终止 forEach。【参考方案2】:

return false; 语句只将值返回给它所属的函数,即

(item, x) => 
      for(let i = 0; (i < band[y].length - x) && (i < band.length - y); i++)         
        if (band[y][x] !== band[y+i][x+i]) 
          console.log(false) //FALSE GETS OUTPUTTED MULTIPLE TIMES
          return false;
        
      
    

您的代码必须以一种可以将 false 返回给主函数的方式工作,您可以使用这种方法:

const isDiagonalLeftWristband = (band) => 
  let returnValue = true;
  band.forEach((row, y) => 
    row.forEach((item, x) => 
      for(let i = 0; (i < band[y].length - x) && (i < band.length - y); i++)         
        if (band[y][x] !== band[y+i][x+i]) 
          console.log(false) //FALSE GETS OUTPUTTED MULTIPLE TIMES
          returnValue = false;
          // return false;
        
      
    )
  )
  return returnValue;

domondo 建议的更好,因为一旦找到第一个 false,该函数就存在

【讨论】:

以上是关于具有嵌套 forEach 和 for 循环的函数不会返回 false的主要内容,如果未能解决你的问题,请参考以下文章

在 VBA 中是不是有循环类型、函数或方法来清理 HTML 文件中节点的嵌套 For Each 循环?

CUDA:并行化具有嵌套循环的函数调用的多个嵌套for循环

foreach嵌套遍历循环的问题

使用具有多个参数和索引的lapply / sapply减少函数内的嵌套循环

在R中将嵌套的for循环转换为并行

如何在 Nightwatch 测试的自定义命令中添加嵌套函数 javascript - forEach - 循环遍历元素