【问题标题】:Can't detect the cause of infinite loop in a 'while loop' in JS无法在 JS 的“while 循环”中检测到无限循环的原因
【发布时间】:2019-10-11 17:09:02
【问题描述】:

我的 while 循环中有一个无限循环,我找不到原因。

这是一个简单的函数,它返回参数数字的总和。我使用了一个while循环,因为它需要将数字相加,直到它到达一个数字。 我确保我添加了一个语句,以确保在某个点循环会中断。但显然不会。

function digital_root(n) {
 num = n;
 sum = 0;
 while (num.toString().length>1){
      for (i=0; i<num.toString().length; i++) {
           sum += parseInt(num.toString()[i])    
       }
       num = sum;
  }
  return sum;
}
digital_root(456)

我收到警告说我在第 4 行有一个无限循环(while 循环)。 我希望num=sum 将新整数(位数减少)重新分配给numvariable,从而在某个时候跳出循环。这是错的吗?

让我更加困惑的是,我用来调试问题的大多数 JS 编辑器都会返回输出,但这需要很长时间。那么它是一个无限循环还是不是?

【问题讨论】:

    标签: javascript loops while-loop infinite-loop


    【解决方案1】:

    您有一个嵌套循环结构,其中第一个条件始终为真。

    如果只得到一个小于 10 的数字,您可以再次调用该函数作为递归。

    function digital_root(n) {
        var num = n.toString(), // declare and use the string value
            sum = 0,
            i;
    
        for (i = 0; i < num.length; i++) {
            sum += parseInt(num[i], 10)
        }
        return sum > 9
            ? digital_root(sum)
            : sum;
    }
    
    console.log(digital_root(456));

    【讨论】:

    • 感谢您的回答,尼娜。但这还没有解决我的问题。这里的挑战是,只要总和 > 9,我就需要不断地将总和的数字相加。或者换句话说,函数必须返回一个数字整数。这就是我首先使用 while 循环的原因。有什么想法吗?
    【解决方案2】:

    重新阅读问题后,我注意到您正在尝试将整数减少为单个数字。您的代码的问题是 sum 设置为 0,仅在 while 循环之前。这意味着它没有在第二次、第三次……运行时重置。

    sum = 0 移入while 循环可解决此问题。我还在顶部添加了变量声明以避免设置全局变量。

    function digital_root(n) {
      var num, sum, i;
    
      num = n;
      while (num.toString().length > 1) {
        sum = 0;
        for (i = 0; i < num.toString().length; i++) {
          sum += parseInt(num.toString()[i]);
        }
        num = sum;
      }
      return sum;
    }
    
    console.log(digital_root(456));

    这里是递归写的,个人比较喜欢的一种风格:

    function digital_root(integer) {
      // guard against things that might result in an infinit loop, like floats
      if (!Number.isInteger(integer) || integer < 0) return;
      
      const chars = integer.toString().split("");
      if (chars.length == 1) return integer;
      
      return digital_root(
        chars.map(char => parseInt(char))
             .reduce((sum, digit) => sum + digit)
      );
    }
    
    console.log(digital_root(456));

    【讨论】:

    • 非常感谢,3limin4t0r!我对您的第二版代码感到有些困惑。我从没想过可以在同一个函数中返回函数调用而不是 while 循环。哇!
    • @EliFabrikant 谢谢。当我第一次阅读这个问题时,我没有注意到这句话“我使用了一个while循环,因为它需要将数字相加,直到它到达一个数字。”,所以我提高了@987654322 @。只有在我重新阅读之后,我才注意到这不是您正在寻找的答案。这个问题的表述很好,但我想这个问题被太多的噪音包围了。我不太确定我会如何提出这个问题,也许把要求放在一个列表中。在这里,人们经常会跳过一半的内容。
    【解决方案3】:

    既然你已经得到了答案,那么这里有另一种方式来满足结果

    function digital_root(n) {
      // convert the number to string
      // use split to create an array of number viz ['4','5','6']
      // use reduce to sum the number after converting to number
      // 0 is the initial value
      return n.toString().split('').reduce((a, c) => a + parseInt(c, 10), 0)
    }
    console.log(digital_root(456))

    【讨论】:

    • 感谢您的回答,brk,但就像我写 Nina 一样,这还没有解决我的问题。这里的挑战是,只要总和 > 9,我就需要不断地将总和的数字相加。或者换句话说,函数必须返回一个数字整数。这就是我首先使用 while 循环的原因。有什么想法吗?
    【解决方案4】:

    避免所有导致您面临的情况的嵌套循环,我宁愿以更易读的方式来做。

    function digital_root(n) {
        sum = n;
    
        while(sum.toString().length > 1) {
            sum = sum.toString()
           .split('')
           .map(digit => parseInt(digit, 10))
           .reduce((acc, cur) => acc + cur);
        }
    
        return sum;
    }
    
    console.log(digital_root(456));
    

    【讨论】:

    • 感谢您的回答,阿哈萨米姆。但是您错过了问题的一个重要元素:该函数必须返回一位整数。因此循环。
    • 对不起,我想我忽略了它,虽然你已经得到了答案,但我刚刚更新了答案中的代码,使其满足要求。
    猜你喜欢
    • 2015-12-11
    • 2018-03-12
    • 2012-12-24
    • 2014-03-29
    • 1970-01-01
    • 2015-06-25
    • 1970-01-01
    • 1970-01-01
    • 2013-02-22
    相关资源
    最近更新 更多