0

I've been learning javascript in school for a few months now and I'm trying to work a problem out on my own but I can't seem to figure out what the issue is. The assignment is to "Create a for loop that starts at zero and loops once for each character in the number using the .length property." So for example, if I were to put in 2514 it should return 12. Here is the piece I'm struggling with

function sumOfDigits(numberPassed) {

    if (!isNaturalNumber(numberPassed)) {
        return 'bad data';
    } else {
        numberPassed = parseInt(numberPassed)
        let digitSum = 0;
        for (let i = 0; i < numberPassed.length; i++) {
            digitSum = numberPassed[i] + digitSum;

        }
        return digitSum;
    }
}

When I test it in the browser it keeps giving me 0. If anyone could point me in the right direction I would greatly appreciate it.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • 2
    Once you call `parseInt()`, `numberPassed` is a **number**, not a string, and it doesn't have a `.length`. – Pointy Oct 13 '22 at 18:25
  • 1
    Don't parse numberPassed, parse numberPassed[i] (conver to string) https://jsfiddle.net/zb5wa0y2/ – Hanlet Escaño Oct 13 '22 at 18:26
  • 1
    Yeah you lose the length property and also you can't refer to each digit by index (numberPassed[i] will only work if numberPassed is a string). – James Oct 13 '22 at 18:28
  • If you’ll remove this line numberPassed = parseInt(numberPassed) your code would work just fine. Other wise once you’ve casted the input to type number, then you’ll need to take each digit by taking mod of 10 and then add them. – Dheeraj Sharma Oct 13 '22 at 18:33
  • I have to include the parseInt() and the .length into this it says in the instructions so maybe my order is messed up. When I remove the line numberPassed=parseInt(numberPassed) and test it with 2514 I get 41520 instead of 12 – user20234104 Oct 13 '22 at 18:33
  • @user20234104 look at my jsfiddle – Hanlet Escaño Oct 13 '22 at 18:35
  • let sum = 0; while (passedNumber !== 0) { sum = sum + passedNumber % 10; passedNumber = Math.round(passedNumber / 10); } return sum; – Dheeraj Sharma Oct 13 '22 at 18:40
  • Note that this can also be done as a single line by splitting up the number string and then reducing that array to a single number: `const digitSum = numberPassed.split(``).reduce( (tally, digit) => tally += parseInt(digit), 0)` (being pretty much exactly what the `reduce` function was invented to do =) – Mike 'Pomax' Kamermans Oct 13 '22 at 18:48

3 Answers3

1

function sumOfDigits(numberPassed) {

    if (!isNaturalNumber(numberPassed)) {
        return 'bad data';
    } else {
        numberPassed = parseInt(numberPassed)
        let digitSum = 0;
        for (let i = 0; i < numberPassed.toString().length; i++) {
            digitSum = numberPassed[i] + digitSum;

        }
        return digitSum;
    }
}

It seems that your implementation is incredibly close to the solution that I found.

What the problem is, is that the value of parseInt(numberPassed) is no longer a string, which means its length cannot be read. So you have to one of many solutions. For example:

  1. Make numberPassed a string in the for loop by doing for (let i = 0; i < numberPassed.toString().length; i++)

  2. Don't parse the numberPassed until it is ready to be used as a number. Or create a secondary variable that is the same just set to a string.

There are many other solutions to this problems, but for the most part it is moving around the parseInt() or the .toString() around with the numberPassed, so to make it easier in the future you can use variables similar to intNumberPassed = parseInt(numberPassed) and stringNumberPassed = numberPassed.toString() if you need to switch between the two often

If you would like more of an explanation or more solutions to the problem here they are.

So when you have a string you can measure the length easily, but when you convert it to a number, instead of a list of binary numbers like a word would be, it is a singular value, aka 12 would be 1100 but when you convert it to a string '12' is would be equivalent to 00110001 00110010 which are the unicode to binary values for '12', giving us a length of two, instead of a length of one.

0

parseInt() would convert numberPassed into a number. Thus, you wont be able to perform .length method to it.

You'd have to convert it into a string through, numberPassed.toString() and then while you are performing your addition, convert each digit back to INT through parseInt(numberPassed[i]) to get your desired result.

The code would look something like this,

function sumOfDigits(numberPassed) {

    if (!isNaturalNumber(numberPassed)) {
        return 'bad data';
    } else {
        numberPassed = numberPassed.toString()
        let digitSum = 0;
        for (let i = 0; i < numberPassed.length; i++) {
            digitSum = parseInt(numberPassed[i]) + digitSum;

        }
        return digitSum;
    }
}
0

Do not parse your number string into an int, if you want to loop over each digit like it was an array.

function isNaturalNumber(numberStr) {
  return /^\d+$/.test(numberStr);
}

function sumOfDigits(numberPassed) {
  if (!isNaturalNumber(numberPassed)) {
    return 'bad data';
  } 
  let digitSum = 0;
  for (let i = 0; i < numberPassed.length; i++) {
    digitSum += parseInt(numberPassed[i], 10);
  }
  return digitSum;
}

console.log(sumOfDigits('2514')); // 12

If you want to parse it first, you will have to use some logarithmic math to extract each digit. String manipulation is less expensive in JavaScript, so this one is much-less performant.

function numDigits(n) {
  return Math.max(Math.floor(Math.log10(Math.abs(n))), 0) + 1;
}

function getDigit(n, offset, fromLeft) {
  const magnitude = fromLeft ? numDigits(n) - offset : offset + 1;
  return Math.floor((n / Math.pow(10, magnitude - 1)) % 10);
}

function isNaturalNumber(numberStr) {
  return /^\d+$/.test(numberStr);
}

function sumOfDigits(numberPassed) {
  if (!isNaturalNumber(numberPassed)) {
    return 'bad data';
  }
  const natural = parseInt(numberPassed, 10);
  const digits = numDigits(natural);
  let digitSum = 0;
  for (let i = 0; i < digits; i++) {
    digitSum += getDigit(natural, i);
  }
  return digitSum;
}

console.log(sumOfDigits('2514')); // 12

Credit for getDigit calculation: https://stackoverflow.com/a/41712226/1762224


If you want the most ES6 way to achieve this, give this a shot:

/**
 * Determines if a given string is a natural number.
 * @param {string} numStr - A number string
 * @returns {boolean} The given string represents a natural number
 */
const isNaturalNumber = numStr => /^\d+$/.test(numStr)

/**
 * Sums the digits of a given number or number string.
 * @param {(number|string)} num - A number or number string
 * @returns {number} The sum of all the digits
 */
const sumOfDigits = num =>
  (numStr =>
    isNaturalNumber(numStr)
      ? numStr.split('').reduce((sum, d) => sum + parseInt(d, 10), 0)
      : 'bad data')
  (num ? num.toString() : '')

console.log(sumOfDigits(2514))   // 12
console.log(sumOfDigits('2514')) // 12
console.log(sumOfDigits(5e2))    // 5
console.log(sumOfDigits('5e2'))  // 'bad data'
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132