Summing a number's digits - javascript

My code below. Can someone see the mistake I made?
Write a function named sumDigits which takes a number as input and returns the sum of the absolute value of each of the number's decimal digits. For example:
sumDigits(10); // Returns 1
sumDigits(99); // Returns 18
sumDigits(-32); // Returns 5
Let's assume that all numbers in the input will be integer values.
function sumDigits(number) {
let numberstring = number.toString()
let numberarr = numberstring.split("")
let counter = 0
for(var i=0; i<numberarr.length; i++) {
if(typeof numberarr[i] === "number") {
console.log(numberarr[i])
let numbervalue = Number(numberarr[i])
console.log(numbervalue)
counter += numbervalue
} else if (typeof numberarr[i] !== "number"){
counter += 0
}
}
return counter
}

console.log(Math.abs(sumDigits(10))); // Returns 1
console.log(Math.abs(sumDigits(99))); // Returns 1
console.log(Math.abs(sumDigits(-32))); // Returns 1 // Returns 5
//Let's assume that all numbers in the input will be integer values.
function sumDigits(number) {
var counter = 0;
var remainder;
number=Math.abs(number);
while(number>0){
counter=counter+number%10;
number=Math.floor(number/10);
}
return counter;
}
I think you are looking for some code like this. i don't get why you convert your number to string.
number=Math.abs(number); this line first convert any negative number to positive.
sumDigits(number) takes an argument as now loop through the number until number < 0 then add the remainder to counter variable then return counter as final sum

Try this solution:
console.log(sumDigits(-103)); // Returns 4
function sumDigits(number) {
var numberstring = number.toString();
var counter=0;
for(var i=0; i<numberstring.length; i++){
if(parseInt(numberstring.charAt(i))){
counter += parseInt(numberstring.charAt(i));
}
}
return counter;
}

This
if(typeof numberarr[i] === "number")
statement is always false, because before you convert the number into a string. I think that your function return always zero.

The answer by giovybus & Raman are correct, if you were wondering why your snippet didn't work - it's because the reference of the numberer[I] will always be a string. numberarr is a string array, not a number array, you needed to convert it to a number before using. Adjustments to your code above as below
sumDigits(10); // Returns 1
sumDigits(99); // Returns 18
sumDigits(-32);
function sumDigits(number) {
let numberstring = number.toString().replace("-", "");
let numberarr = numberstring.split("")
let counter = 0
for(var i=0; i<numberarr.length; i++) {
const numbervalue = Number(numberarr[i])
if(typeof numbervalue === "number") {
counter += numbervalue
} else if (typeof numbervalue !== "number"){
counter += 0
}
}
console.log(counter)
return counter
}
However this is not a good solution and you should consider using solution by giovybus, Raman or anyone else with better approach instead.

Using filter and reduce to calculate the total.
function sumDigits(number) {
return ( [...number.toString()]
.filter( (char) => !isNaN(parseInt( char ) ) )
.reduce( function(a,b) { return a + parseInt(b) }, 0) );
}
const sum1 = sumDigits(103);
console.log( sum1 );
const sum2 = sumDigits(-105);
console.log( sum2 );

Using latest ES6 syntax...
function sumDigits(num) {
return [...num.toString()].map(Number).reduce((acc, val) => acc + val, 0);
};
console.log(sumDigits(55)); // 10
Explanation of tricky parts:
This will split the string into an array of digits:
[..."1234"] // => [ "1", "2", "3", "4" ]
This will transform it into Numbers
[ "1", "2" ].map(Number) // => [ 1, 2 ]

Related

Codwars: Array to single value +1

Given an array of integers of any length, return an array that has 1 added to the value represented by the array.
the array can't be empty
only non-negative, single digit integers are allowed
Return nil (or your language's equivalent) for invalid inputs.
Examples
For example the array [2, 3, 9] equals 239, adding one would return the array [2, 4, 0].
My code so far:
function upArray(arr){
let i = parseInt(arr.join('')) + 1;
return arr.some(e => typeof e !== 'number' || e < 0) ?
null : i
.toString()
.split('')
.map(e => parseInt(e));
};
It seems to pass most basic test however fails with larger inputs. Where have I gone wrong?
Just like you have converted the array into a number, you have to convert the number back into an array.
function upArray(arr){
let i = parseInt(arr.join('')) + 1;
return i.toString().split('').map(x => parseInt(x));
};
console.log(upArray([2,3,9]));
Your code won't work if the array length is greater than 100k...
Number type of javascript or any language is not enough big to handle it.
It's better if we calculate the last element with 1. If result is larger than nice ( < 10 ),
we continue to calculate next element with 1 and assign current value to 0. If result is smaller or equal 9, just assign the result to current and exit loop.
Then we print the final array as result:
pseudo code:
for i from: n-1:0
result = arr[i] + 1;
if(result < 10) :
arr[i] = result;
exit loop;// no need to continue calculate
else:
arr[i] = 0;
endif;
endfor;
You can join final array as string.
Here's probably the fastest solution (performance wise) - also there's no need to deal with BigInt, NaN, or Infinity:
function upArray(arr) {
if (!isInputIsNonEmptyArray(arr)) {
return null;
}
const isNumber = num => typeof num === 'number';
const isIntSingleDigit = num => Number.isInteger(num) && num >= 0 && num <10;
let resultArr = [];
let i = arr.length;
let num;
while (i-- > 0) {
num = arr[i];
if (!isNumber(num) || !isIntSingleDigit(num)) {
return null;
}
if (num === 9) {
resultArr[i] = 0;
if (i === 0) { //means we're in the msb/left most digit, so we need to insert 1 to the left
resultArr.unshift(1);
break; //you can leave it out really, as the next check in the while will fail anyway
}
}
else {
resultArr[i] = num + 1; //No more + 1 should be made, just check for validity
//of the rest of the input and copy to the result arr
while (--i > -1) {
num = arr[i];
if (!isNumber(num) || !isIntSingleDigit(num)) {
return null;
}
resultArr[i] = arr[i];
}
break;
}
}
return resultArr;
function isInputIsNonEmptyArray(arr) {
return Array.isArray(arr) && arr.length > 0;
}
}
If the input arg is not an array or an empty array, or if you encounter invalid element during the main while loop you return null.
In the main while loop you go from the right most element (lsd), and add 1 to it (or insert 0 if the number is 9) up the the left most digit.
If a number which is less than 9 is incremented, no need to increment any more (this is the while loop in the else clause).

How can I count the number and calculate it? (i using isNaN())

My code is below. I'm using isNaN() but the problem is it's still valid
function numberSearch(str) {
let sum = 0
let strCount = 0
if (str === "") {
return 0
};
for (let i = 0; i < str.length; i++) {
if (isNaN(Number(str[i]))) {
strCount = strCount + 1 // if it's true, +1
}
sum = sum + Number(str[i]) // if it's a number
}
return Math.round(sum / strCount);
}
//debugger;
let output = numberSearch('Hello6 ');
console.log(output); // --> 1
output = numberSearch('Hello6 9World 2,');
console.log(output); // --> 1
How can I count the number and calculate it?
When I using debugger sum is NaN .. I cant understand well.
The issue is that sum = sum + Number(str[i]) is being executed even if isNaN(Number(str[i])) === true because it is outside of the if block. You need to wrap it inside of the else block so that it only executes if the previous condition is false.
function numberSearch(str) {
let sum = 0
let strCount = 0
if (str === "") {
return 0
};
for (let i = 0; i < str.length; i++) {
if (isNaN(Number(str[i]))) {
strCount = strCount + 1 // if it's true, +1
} else {
sum = sum + Number(str[i]) // if it's a number
}
}
return Math.round(sum / strCount);
}
//debugger;
let output = numberSearch('Hello6 ');
console.log(output); // --> 1
output = numberSearch('Hello6 9World 2,');
console.log(output); // --> 1
The other way of doing this is with a continue statement. Think of continue the same way you think about an early return in a function, except for a loop.
For example, you've written:
function numberSearch(str) {
// . . .
if (str === "")
return 0
// . . .
}
This is called an "early return" or "early exit." The same technique can be used in a loop:
for (let i = 0; i <= 10; i++) {
if (i % 3 === 0) // matches every multiple of 3 (3, 6, 9, etc.)
continue;
console.log(i)
}
Here is your code again, this time using continue.
function numberSearch(str) {
let sum = 0
let strCount = 0
if (str === "") {
return 0
};
for (let i = 0; i < str.length; i++) {
if (isNaN(Number(str[i]))) {
strCount = strCount + 1 // if it's true, +1
continue
}
sum = sum + Number(str[i]) // if it's a number
}
return Math.round(sum / strCount);
}
//debugger;
let output = numberSearch('Hello6 ');
console.log(output); // --> 1
output = numberSearch('Hello6 9World 2,');
console.log(output); // --> 1
I recommend you go with the if-else version because for a loop as simple as this, the use of continue adds a little unnecessary metal-overhead.
That being said, if the logic within the loop grows (the part in the else statement), you may find it is easy to read if you do use the continue method. In the end, what really matters is what you personally feel is easier to read.
I would probably do it slightly different than in the original code, and find out how many numbers there are, and work from there
function numberSearch(str) {
if (!str) {
// early exit for null or ''
return 0;
}
// get all the chars, filter the non-numbers
const numbers = str.split('').filter( v => !isNaN(Number(v)));
// map all the numbers to numbers and sum them up
const sum = numbers.map( Number ).reduce( (agg, item) => agg + item, 0 );
// divide the sum by the length of the string - the amount of numbers found
// but always by at least 1 (so not to get a divide by 0 error when only all numbers are given)
return Math.round( sum / Math.max(1, str.length - numbers.length) );
}
let output = numberSearch('Hello6 ');
console.log(output); // --> 1
output = numberSearch('Hello6 9World 2,');
console.log(output); // --> 2
output = numberSearch('111111111');
console.log(output); // --> 9
output = numberSearch('');
console.log(output);
For the original code however, you should just add a continue in your if branch and your code will work (as long as not all characters are numbers, cause then you would divide by 0 and you didn't specify how to handle such a case)
for (let i = 0; i < str.length; i++) {
if (isNaN(Number(str[i]))) {
strCount = strCount + 1; // if it's true, +1
continue;
}
sum = sum + Number(str[i]); // if it's a number
}
Just remember to verify to not divde by 0 if all are numbers :)
Your main issue is that you add a number anyway. In the line sum = sum + Number(str[i]) is read for each and every character. So even the last char will be NaN and it would be added to the sum, making it NaN.
I'm not quite sure what you're trying to do here, it seems like you are trying to get the sum and divide it by the number of non number characters.
You need to skip those in the sum. There are plenty of ways to do it, and some other problems with the code, but to keep the changes to your code to a minimum I say, just do this:
function numberSearch(str) {
let sum = 0;
let strCount = 0;
if (str === "") {
return 0;
};
for (let i = 0; i < str.length; i++) {
if (isNaN(Number(str[i]))) {
strCount = strCount + 1; // if it's true, +1
} else {
sum = sum + Number(str[i]); // if it's a number
}
}
return Math.round(sum / strCount);
}
Think of the following case
for(let i = 0 ; i<str.length ; i++){
//str[0] is 'H', so fall into the first if-case
if(isNaN(Number(str[i]))){
strCount = strCount + 1 // if it's true, +1
}
//the code keep running but 'H' shouldn't fall into the following case
sum = sum + Number(str[i]) // if it's a number
}
return Math.round(sum/strCount);
I suggest you add one more if-else for each case which clearly state out each of the case. This makes it easier to recall memory when you come across the code days or months later.
for(let i = 0 ; i<str.length ; i++){
if(isNaN(Number(str[i]))){
strCount = strCount + 1
}else if(typeof str[i] === 'number'){
sum = sum + Number(str[i])
}
}
return Math.round(sum/strCount);

Transform this iteration function to recursive

This is a function to display the sum of the input digits with iteration perspective:
function sumOfDigits(number) {
let strNumber = number.toString()
let output = 0;
for(i=0;i<strNumber.length;i++){
let tmp = parseInt(strNumber[i])
output = output + tmp
}
return output
}
// TEST CASES
console.log(sumOfDigits(512)); // 8
console.log(sumOfDigits(1542)); // 12
console.log(sumOfDigits(5)); // 5
console.log(sumOfDigits(21)); // 3
console.log(sumOfDigits(11111)); // 5
I am wondering how we write this function in a recursive way?
Using the modulo operator, you can get the remainder (which in the case of a divison by 10, is the last number) and then add the next iteration.
function sumOfDigits (n) {
if (n === 0) return 0
return (n % 10 + sumOfDigits(Math.floor(n / 10)))
}
console.log(sumOfDigits(512))
If you want to see a more detailed explanation, check https://www.geeksforgeeks.org/sum-digit-number-using-recursion/
I have not tested it, but you can try the following without casting to string
function sumOfDigits(number)
{
if (number === 0) {
return 0;
}
return (number % 10 + sumOfDigits(Math.floor(number / 10)));
}
Make sure that the input is indeed in number format
Here you go
function sumOfDigitsRecursive(number){
let strNumber = number.toString()
if(strNumber.length<=0)
return 0
return parseInt(strNumber[0])+sumOfDigitsRecursive(strNumber.slice(1,strNumber.length))
}

To determine whether a number and any other two numbers in the array to form a continuous number of three

write a function like this:
function canFormContinuosNums(num, array);
//num is the target number,
//array is the source array which contain some int number:
for example:
num = 1,
array =[ 2,3,4,5,7,8,9,0];
the function must test weather the array contain two number such as 2,3 or 0,2, can form '012' or '123'.
The function must return false or true ;
if true return the two array ,like [2,3] or [0,2];
I tried a lot, but neither work perfect.Thanks a lot for your help.
How about this one?
function canFormContinuosNums(num, array) {
var tempArray = new Array();
var outputArray = new Array();
for (var i = 0; i < 3; i++) {
tempArray[i] = [num+i-2, num+i-1, num+i];
tempArray[i].splice(tempArray[i].indexOf(num), 1);
var check = 0;
for (var k = 0; k < tempArray[i].length; k++) {
if (array.includes(tempArray[i][k])) {
check += 1;
}
}
if (check == 2) {
outputArray.push(tempArray[i]);
}
}
console.log(outputArray);
};
num = 4,
array =[2,3,4,5,7,8,9,0];
canFormContinuosNums(num, array);
You can try something like this:
Logic:
Find the index where number is to be inserted.
Now loop over partial range:
Start from 0 or index-2 to capture previous elements.
Stop loop at index + 2. This may result in exceeding bounds.
Now validate, if value exists and the difference between next and current element is 1 increment count.
Now compare if count is greater than on equal to your required continuous length (2 in your case) and return accordingly.
function canMakeContinuous(arr, num) {
if(arr.indexOf(num) > -1) return false
var copy = arr.slice();
var index = 0;
arr.some(function(item, i) {
index = i;
if (item > num) {
return true;
}
});
copy.splice(index, 0, num)
var count = 0;
for (var i = Math.max(index - 2, 0); i < index + 3; i++) {
if (copy[i + 1] !== undefined && copy[i + 1] - copy[i] === 1) {
count++;
} else if (count < 2) {
count = 0;
}
}
return count > 1
}
var array = [2, 3, 4, 7, 8, 9, 0];
canMakeContinuous(array, 1)
canMakeContinuous(array, 6)
canMakeContinuous(array, 5)
canMakeContinuous(array, 9)
function canFormContinuousNums(num, array){
// array contains the 2 numbers before num
if(array.indexOf(num-2)!=-1 && array.indexOf(num-1)!=-1){
return [num-2,num-1];
}
// array contains the number before num AND the number after num
else if(array.indexOf(num-1)!=-1 && array.indexOf(num+1)!=-1){
return [num-1,num+1];
}
// array contains the 2 numbers after num
else if(array.indexOf(num+1)!=-1 && array.indexOf(num+2)!=-1){
return [num+1,num+2];
}
return false;
}
This should give you wether the array contains two numbers such as you can form a continuous number of three, and if you can, will return either the array containing the 2 previous numbers, or the one containing the one before and the one after, or the one containing the two next numbers.
You could also have a code for which combination is doable as :
0 -> no combination
1 -> the two previous numbers
2 -> the one before & the one after
4 -> the two next numbers
And then :
3 will give you both 1 & 2
5 will give you both 1 & 4 // note that 1 & 4 is impossible without 2
6 will give you both 2 & 4
7 will give you all three combinations.
As following :
function canFormContinuousNums(num, array){
var result = 0;
// array contains the 2 numbers before num
if(array.indexOf(num-2)!=-1 && array.indexOf(num-1)!=-1){
result += 1;
}
// array contains the number before num AND the number after num
if(array.indexOf(num-1)!=-1 && array.indexOf(num+1)!=-1){
result += 2;
}
// array contains the 2 numbers after num
if(array.indexOf(num+1)!=-1 && array.indexOf(num+2)!=-1){
result += 4;
}
return result;
}
var array = [0,1,4,6,8,9,11,14,15,17,18];
console.log(canFormContinuousNums(20, array)); // no combination
console.log(canFormContinuousNums(2, array)); // [0,1]
console.log(canFormContinuousNums(5, array)); // [4,6]
console.log(canFormContinuousNums(10, array)); // [8,9] & [9,11]
console.log(canFormContinuousNums(13, array)); // [14,15]
console.log(canFormContinuousNums(7, array)); // [6,8] & [8,9]
console.log(canFormContinuousNums(16, array)); // [14,15] & [15,17] & [17,18]
// test function to display all the combinations switch the number and the result given by canFormContinuousNums
function displayResult(number,result){
if(result & 1){
console.log("["+(number-2)+","+(number-1)+"]");
}
if(result & 2){
console.log("["+(number-1)+","+(number+1)+"]");
}
if(result & 4){
console.log("["+(number+1)+","+(number+2)+"]");
}
}
console.log("Test displayResult(16,7)");
displayResult(16,canFormContinuousNums(16,array));
Edit :
As you wish to get all the combinations, the following should work :
function canFormContinuousNums(num, array){
var flag = false;
var result = [[0,0],[0,0],[0,0]];
// array contains the 2 numbers before num
if(array.indexOf(num-2)!=-1 && array.indexOf(num-1)!=-1){
flag = true;
result[0][0] = num-2;
result[0][1] = num-1;
}
else{
result[0] = false;
}
// array contains the number before num AND the number after num
if(array.indexOf(num-1)!=-1 && array.indexOf(num+1)!=-1){
flag = true;
result[1][0] = num-1;
result[1][1] = num+1;
}
else{
result[1] = false;
}
// array contains the 2 numbers after num
if(array.indexOf(num+1)!=-1 && array.indexOf(num+2)!=-1){
flag = true;
result[2][0] = num+1;
result[2][1] = num+2;
}
else{
result[2] = false;
}
if(flag == true){
return result;
}
else{
return false;
}
}
var array2 = [0,1,2];
console.log(canFormContinuousNums(1,array2));
console.log(canFormContinuousNums(4,array2));

function sumDigits; How do I get this function to work with a negative number?

Question:
Write a function called sumDigits.
Given a number, sumDigits returns the sum of all its digits.
var output = sumDigits(1148);
console.log(output); // --> 14
If the number is negative, the first digit should count as negative.
var output = sumDigits(-316);
console.log(output); // --> 4
This is what I currently have coded and it works for positive values but I can't wrap my head around how to tackle the problem when given a negative value. When -316 is put into the function, NaN is returned and I understand that when I toString().split('') the number, this is what is returned: ['-', '3', '1', '6']. How do I deal with combining index 0 and 1?
function sumDigits(num) {
var total = 0;
var newString = num.toString().split('');
for (var i = 0; i < newString.length; i ++) {
var converted = parseInt(newString[i]);
total += converted;
}
return total;
}
sumDigits(1148);
Any hints on what methods I should be using? and is there a smarter way to even look at this?
This should do it:
function sumDigits(num) {
var total = 0;
var newString = num.toString().split('');
for (var i = 0; i < newString.length; i ++) {
if(newString[i]==='-') { //check to see if the first char is -
i++; //if it is, lets move to the negative number
var converted = parseInt(newString[i]); // parse negative number
total -= converted; // subtract value from total
continue; // move to the next item in the loop
}
var converted = parseInt(newString[i]);
total += converted;
}
return total;
}
console.log(sumDigits(-316));
You could always use String#replace with a function as a parameter:
function sumDigits (n) {
var total = 0
n.toFixed().replace(/-?\d/g, function (d) {
total += +d
})
return total
}
console.log(sumDigits(-1148)) //=> 14
One way to do this, is to do a split that will keep the minus and the first digit together, not split.
You can do that with a regular expression, and use match instead of split:
var newString = num.toString().match(/-?\d/g);
function sumDigits(num) {
var total = 0;
var newString = num.toString().match(/-?\d/g);
for (var i = 0; i < newString.length; i++) {
var converted = parseInt(newString[i]);
total += converted;
}
return total;
}
var result = sumDigits(-316);
console.log(result);
In a bit shorter version, you could use map and reduce, like this:
function sumDigits(num) {
return String(num).match(/-?\d/g).map(Number).reduce( (a, b) => a+b );
}
console.log(sumDigits(-316));
Is there a smarter way to even look at this?
You can avoid the conversion from number to string and back by using the modulo operator to extract the last digit. Repeat this step until you got all digits:
function sumDigits(num) {
let total = 0, digit = 0;
while (num != 0) {
total += digit = num % 10;
num = (num - digit) * 0.1;
}
return total < 0 ? digit + digit - total : total;
}
console.log(sumDigits(-316)); // 4
console.log(sumDigits(1148)); // 14
console.log(sumDigits(Number.MAX_SAFE_INTEGER)); // 76
function sumDigits(num) {
let string = num.toString();
let zero = 0;
let total = 0;
for (var i = 0; i < string.length; i++) {
if (Math.sign(num) === 1) {
total = zero += Number(string[i]);
} else {
for (var i = 2; i < string.length; i++) {
total = (zero += Number(string[i])) - Number(string[1]);
}
}
}
return total;
}

Categories

Resources