简体   繁体   中英

While loop with two nested for loops outputting infinite loop, what am I doing wrong?

I am making a program that takes any random integer add up its individual values and create a sum. If the length of the sum when converted to string form is greater than 1, we continue the process of adding the integer values together until we reach a sum with 1 digit.

My issue with the code is that my expected output for random numbers with a value of 1 digit already will return the number immediately, if the numbers with digits greater than 1 add up to another greater than 1 digit number, it will not repeat the loop but rather be stuck in an infinite loop.

let digitalRoot = (n) => {
  let stringNum = n.toString();
  let refArr = [];
  let result = 0;
  let iterator = refArr.values();

  while (stringNum.length > 1) {
    
    for (let i = 0; i < stringNum.length; i++) {
      let stringVal = stringNum[i];
      stringVal = parseInt(stringVal);
      refArr.push(stringVal)
    }
    
    for (let number of iterator) {
      if (result !== number) {
        result = result + number;
      }
      else {
        result = result + number;
      }
    }
    
    result = result.toString();
    if (result.length === 1) {
      result = parseInt(result);
      return result;
    }

    refArr = [];
    stringNum = result.toString();

  }

  if (stringNum.length === 1) {
    stringNum = parseInt(stringNum);
    return stringNum;
  }

}

expected output for 1455 , for example, should be 6 , because 1 + 4 + 5 + 5 = 15 ; 1 + 5 = 6

UPDATE

I know my original code in the question was inefficient but I was able to get my intended result by editing a few things, first was moving the refArr & iterator variables into the while loop, resetting the result to 0 and a few other modifications. Obviously my code is the very very inefficient solution and isn't recommended but I wanted to correct my code as an exercise, etc.

let digitalRoot = (n) => {
  let stringNum = n.toString();
  let result = 0;

  while (stringNum.length > 1) {
    let refArr = [];
    let iterator = refArr.values();

    for (let i = 0; i < stringNum.length; i++) {
      let stringVal = stringNum[i];
      stringVal = parseInt(stringVal);
      refArr.push(stringVal)
    }

    for (let number of iterator) {
      if (result !== number) {
        result = result + number;
      }
      else {
        result = result + number;
      }
    }

    let tester = result.toString();
    if (tester.length === 1) {
      tester = parseInt(tester);
      return tester;
    }

    stringNum = result.toString();
    result = 0;
    refArr = [];
  }

  if (stringNum.length === 1) {
    stringNum = parseInt(stringNum);
    return stringNum;
  }

}

You can do that...

 const digitalRoot = n => { while (n > 10) n = [...n.toString(10)].reduce((s,v)=>s + +v,0) return n } console.log( digitalRoot( 1455 ))

some points...

.toString()
n.toString(10) change 12546 to '12546'

spread syntax (...)
...'123456' change '12546' to '1','2','3','4','5','6' (iterationnal)
so
[...'123456'] make an array = [ '1','2','3','4','5','6' ]

Array.reduce()
and
+v Unary plus (+) just before a string is: as written in the doc:
The unary plus operator (+) precedes its operand and evaluates to its operand but attempts to convert it into a number.

to explain the reduce method used here:
[ '1','2','3','4','5','6' ].reduce((s,v) => s + +v, 0)
do:

step 0  s =  0, v = '1' ->  0 + +'1' =  0 + 1 = 1 
step 1  s =  1, v = '2' ->  1 + +'2' =  1 + 2 = 3 
step 2  s =  3, v = '3' ->  3 + +'3' =  3 + 3 = 6 
step 3  s =  6, v = '4' ->  3 + +'4' =  6 + 4 = 10 
step 4  s = 10, v = '5' -> 10 + +'5' = 10 + 5 = 15 
step 5  return 15

What happens if n is negative? Let's assume n >= 0 for this. It's really unclear why you have 2 loops, and the 2nd one has a test for something but does the same thing regardless.

  • In general, try to avoid making the same variable sometimes a number and sometimes a string. "15" + 1 = "151" while 15 + 1 = 16
  • Reset your accumulators at the start of loops.
  • Rarely a need to grab the iterator before the loop

A simplified version:

let digitalRoot = (n) => {
  while (n >= 10) {
    // convert to decimal
    let stringNum = n.toString();
    let result = 0
    for (let i = 0; i < stringNum.length; i++) {
      result +=  parseInt(stringNum[i]);
    }
    n = result
  }
  return n
}

Much simpler way would be to use reduce() , this higher function iterates over an array of values and reduces the number of those values with each iteration while calculating the accumulated previous value with the next value in the array.

Split the string into an array, then map it back to a Number and reduce adding the accumulator to the return value each iteration.

 const num = 1455; const num2 = 35714; const num3 = 11211; const sumUp = (num) => { return String(num).split('').map(Number).reduce((a, c) => a + c); } console.log(sumUp(num), sumUp(num2), sumUp(num3))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM