Не удается обнаружить причину бесконечного цикла в цикле while в JS - PullRequest
2 голосов
/ 25 мая 2019

У меня внутри бесконечный цикл, и я не могу найти причину.

Это простая функция, которая возвращает сумму цифр аргумента. Я использую цикл 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 переназначит новое целое число (с уменьшенным числом цифр) переменной num и, таким образом, в какой-то момент выйдет из цикла. Это неправильно?

Что меня еще больше смущает, так это то, что большинство редакторов JS, которые я использовал для устранения проблемы, возвращают выходные данные, но это занимает много времени. Так это бесконечный цикл или нет?

Ответы [ 4 ]

4 голосов
/ 25 мая 2019

У вас есть структура с вложенным циклом, в которой первое условие всегда выполняется.

Чтобы получить только число ниже 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));
1 голос
/ 25 мая 2019

Перечитав вопрос, я заметил, что вы пытаетесь уменьшить целое число до одного числа.Проблема с вашим кодом заключалась в том, что 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));
0 голосов
/ 25 мая 2019

Избегая всех вложенных циклов, которые приводят к такой ситуации, с которой вы сталкиваетесь, я бы предпочел сделать это более читабельным способом.

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));
0 голосов
/ 25 мая 2019

Поскольку вы уже получили ответ, вот еще один способ достичь результата

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))
...