baphomet
baphomet

Reputation: 31

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;
  }

}

Upvotes: 0

Views: 366

Answers (3)

dale landry
dale landry

Reputation: 8600

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

Upvotes: 1

Mister Jojo
Mister Jojo

Reputation: 22295

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

Upvotes: 2

Geoduck
Geoduck

Reputation: 9005

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
}

Upvotes: 1

Related Questions