JavaScript recursive function is returning strange value - javascript

Here is my code, why it is returning 13 in place of 4:
const superNumber = (n) => {
let nums = n.toString().split('').map(Number);
let sum = parseInt(nums.reduce((x, y)=> x + y));
console.log('Nums: ',nums, 'Sum: ', sum);
if(sum > 9) {
superNumber(sum);
}
return sum;
}
let result = superNumber(148);
console.log('Ans: ', result);
Here is the console log:
Nums: [1, 4, 8] Sum: 13
Nums: [1, 3] Sum: 4 // Calculated sum
correctly but returning the previous value
Ans: 13

You forgot a return there:
if (sum > 9)
return superNumber(sum);
// ^^^^^^ here you forgot to return
const superNumber = (n) => {
let nums = n.toString().split('').map(Number);
let sum = parseInt(nums.reduce((x, y) => x + y));
console.log('Nums:', nums.toString(), ' Sum:', sum);
if (sum > 9) {
return superNumber(sum);
}
return sum;
}
let result = superNumber(148);
console.log('Ans: ', result);

if you don't want to mess up with the return...
const superNumber = n =>
{
let
nums = Array.from(n.toString(10))
, sum = nums.reduce((s,v) => s + +v, 0)
;
console.log( 'Nums: ', ...nums, ' , Sum: ', sum );
return (sum < 10) ? sum : superNumber(sum);
}
console.log('Ans: ', superNumber(148));

Related

JavaScript sum array using recursion

My task is to sum elements of an array and add it to second parameter (number) using recursion.
Return only gives me last value of sum. I would appreciate any feedback :)
const getArraySum = (numbersArray, initialValue) => {
// let sum = initialValue
// for (let i = 0; i < numbersArray.length; i++) {
// sum += numbersArray[i]
// } return sum
if (numbersArray.length === 0 ) {
return initialValue
} else {
let sum = 0
sum += numbersArray[numbersArray.length-1]
console.log (numbersArray)
numbersArray.pop()
console.log (sum)
getArraySum (numbersArray)
return sum + initialValue
}
};
const result1 = getArraySum([4,7,10], 5)
console.log (result1)
You're ignoring the return value of the recursive call to getArraySum. Instead, you should add it to the returned value:
const getArraySum = (numbersArray, initialValue) => {
if (numbersArray.length === 0) {
return initialValue
}
return numbersArray.pop() + getArraySum(numbersArray, initialValue);
};
const result = getArraySum([4,7,10], 5)
console.log (result)
Note that the initialValue should only be taken into consideration once, in the end condition where the array is empty.
The idea is to split an array into head (=the first element or null for an empty array) and tail (everything else). Then, establish that the sum is head + sum(tail):
let sum = ([head = null, ...tail]) =>
head === null ? 0 : head + sum(tail)
console.log(sum([1,2,3,4]))
Having an initial value is a silly requirement, but it goes the same way:
let sum = ([head = null, ...tail], init = 0) =>
init + (head === null ? 0 : head + sum(tail))
console.log(sum([1, 2, 3, 4], 100))
You could take the single values a summing variable and return immediately if the array is empty.
Otherwise return the function call with a new shorter array and hte sum of sum and the first element.
const
getSum = (numbers, sum = 0) => {
if (!numbers.length) return sum;
return getSum(numbers.slice(1), sum + numbers[0]);
};
console.log (getSum([4, 7, 10], 5));
As long as the array has an element, return last element (pop) plus getArraySum([rest of the array]), otherwise return initial value:
const getArraySum = (numbersArray, initialValue) => {
if (numbersArray.length === 0 ) {
return initialValue
} else {
return numbersArray.pop() + getArraySum(numbersArray, initialValue);
}
};
const result1 = getArraySum([4,7,10], 5)
console.log (result1)

Sum All Numbers in a Range

freecodecamp algorithm challenge. I can't determine at which point in my function I am returning more than one value. The correct return value should be 10. The console.log I print out in this function shows three values, with the one in the middle being the correct one. How do I target this specific value and ignore the other ones?
https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/sum-all-numbers-in-a-range
function sumAll(arr) {
for (let i = 0; i < arr.length; i++){
if (arr[i] != arr[arr.length -1]){
let num = arr[i] + 1;
arr.splice(arr[i], 0, num);
console.log(arr.reduce(function(sum, value) {
return sum + value;
}, 0));
}
}
}
sumAll([1, 4]);
If you extract a range utility function you can do this a lot easier. Without the imperitiveness
const range = (a,b) => Array(Math.abs(a-b)+1).fill(0).map((_,i) => i+Math.min(a,b))
const sumAll = ([a,b]) => range(a,b).reduce((c,d) => c+d,0)
to diagnose exactly what is wrong with your code, A good start is that it isn't returning anything, it is console.logging, so if you replace console.log with return.
The main issue seems to be with this line arr.splice(arr[i], 0, num);. It is not advisable to change the length of the array which is currently under iteration.
function sumAll(arr) {
let num = [];
let x = arr[0];
while (x <= arr[1]) {
num.push(x);
x++;
}
return num.reduce((acc, curr) => {
return acc += curr
}, 0)
}
console.log(sumAll([1, 4]));
You don't need to take the harder way. First you can use a simple for loop and sort and Second you can use recursion which i prefer because you just need one line of code to it. Here are my answers =>
/*function sumAll(arr) {
arr.sort((a, b) => a - b);
let sum = 0;
for (let i = arr[0]; i <= arr[1]; i++) {
sum += i;
}
return sum;
}
console.log(sumAll([1, 4]));*/
function sumAll(arr) {
arr.sort((a, b) => a - b);
return arr[0] == arr[1] ? arr[0] : arr[0] + sumAll([arr[0] + 1, arr[1]])
}
console.log(sumAll([1, 4]));
You can use reacursion like this :
function sumAll(arr) {
arr.sort((a, b) => a - b);
return arr[0] == arr[1] ? arr[0] : arr[0] + sumAll([arr[0] + 1, arr[1]])
}
console.log(sumAll([1, 4]));
Here is another way:
const sumAll = (arr) => {
arr.sort((a, b) => a - b)
return ((arr[0]+arr[1])/2)*((arr[1]-arr[0])+1)
}
function sumAll(arr) {
arr.sort((a, b) => a - b);
return arr[0] == arr[1] ? arr[0] : arr[0] + sumAll([arr[0] + 1, arr[1]])
}
console.log(sumAll([1, 4]));
function sumAll(arr) {
arr.sort((a, b) => a - b);
return arr[0] == arr[1] ? arr[0] : arr[0] + sumAll([arr[0] + 1, arr[1]])
}
console.log(sumAll([1, 4]));

javascript least amount of elements from an integer array that can be used to get to a total value

please can somebody help?
If i have a total or a sum for instance 91
How can I create an array of the least amount of elements needed to get to the total value?
[50, 20, 10 , 5, 3, 2, 1] totaling this array will provide 91.
I know how to perform the opposite function using reduce or like so:
<script>
var numbers = [65, 44, 12, 4];
function getSum(total, num) {
return total + num;
}
function myFunction(item) {
document.getElementById("demo").innerHTML = numbers.reduce(getSum);
}
</script>
Greedy algorithm
Here is a solution using greedy algorithm. Note that this solution will work correctly in case when all the smaller numbers are divisors of all the bigger numbers such as in case [50, 10, 5, 1]. (see dynamic algorithm below this one for solution that can handle any input)
50 mod 10 = 0
50 mod 5 = 0
50 mod 1 = 0
10 mod 5 = 0
10 mod 1 = 0
5 mod 1 = 0
const sum = xs => xs.reduce((acc, v) => acc + v, 0);
function pickSubset(options, total, currentPick) {
if (sum(currentPick) === total) { return currentPick; }
if (options.length === 0) { return null; }
const firstVal = options[0];
let res = null;
if (sum(currentPick) + firstVal > total) {
res = pickSubset(options.slice(1), total, currentPick);
} else {
let opt1 = pickSubset(options, total, currentPick.concat(options[0]));
let opt2 = pickSubset(options.slice(1), total, currentPick.concat(options[0]));
if (opt1 && opt2) {
opt1.length < opt2.length ? res = opt1 : res = opt2
} else if (opt1) {
res = opt1;
} else {
res = opt2;
}
}
return res;
}
const total = 73;
const options = [50, 25, 10, 5, 2, 1];
console.log(pickSubset(options, total, []));
To handle unsorted input you can wrap it in another function and sort it prior to passing it to the main function.
const sum = xs => xs.reduce((acc, v) => acc + v, 0);
function pickSubset(options, total, currentPick) {
const sortedOptions = options.sort((a, b) => b - a);
function _pickSubset(options, total, currentPick) {
if (sum(currentPick) === total) { return currentPick; }
if (options.length === 0) { return null; }
const firstVal = options[0];
let res = null;
if (sum(currentPick) + firstVal > total) {
res = pickSubset(options.slice(1), total, currentPick);
} else {
let opt1 = pickSubset(options, total, currentPick.concat(options[0]));
let opt2 = pickSubset(options.slice(1), total, currentPick.concat(options[0]));
if (opt1 && opt2) {
opt1.length < opt2.length ? res = opt1 : res = opt2
} else if (opt1) {
res = opt1;
} else {
res = opt2;
}
}
return res;
}
return _pickSubset(sortedOptions, total, currentPick);
}
const total = 73;
const options = [50, 25, 10, 5, 2, 1].reverse();
console.log(pickSubset(options, total, []));
Dynamic programming (bottom-up natural ordering approach)
This solution works correctly for any type of input.
function pickSubset(options, total) {
function _pickSubset(options, change, minNums, numsUsed) {
for (let i = 0; i < change + 1; i++) {
let count = i;
let newNum = 1;
let arr = options.filter(v => v <= i);
for (let j of arr) {
if (minNums[i - j] + 1 < count) {
count = minNums[i - j] + 1;
newNum = j;
}
}
minNums[i] = count;
numsUsed[i] = newNum;
}
return minNums[change];
}
function printNums(numsUsed, change) {
const res = [];
let num = change;
while (num > 0) {
let thisNum = numsUsed[num];
res.push(thisNum);
num = num - thisNum;
}
return res;
}
const numsUsed = [];
const numsCount = [];
_pickSubset(options, total, numsCount, numsUsed);
return printNums(numsUsed, total);
}
const options = [50, 10, 5, 2, 1];
console.log(pickSubset(options, 73));
Dynamic programming (top-down memoization approach)
// helper function that generates all the possible solutions
// meaning, all the possible ways in which we can pay the provided amount
// and caches those solutions;
// returns the number of possible solutions but that is not neccessary
// in this case
const _pickSubset = (toPay, options, currentPick, cache) => {
if (toPay < 0) { return 0; }
if (toPay === 0) {
cache.add(currentPick);
return 1;
}
if (options.length === 0) { return 0; }
return _pickSubset(toPay - options[0], options, currentPick.concat(options[0]), cache)
+ _pickSubset(toPay, options.slice(1), currentPick, cache);
};
// memoize only with respect to the first two arguments - toPay, bills
// the other two are not necessary in this case
const memoizeFirstTwoArgs = fn => {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args.slice(0, 2));
if (cache.has(key)) { return cache.get(key); }
const res = fn(...args);
cache.set(key, res);
return res;
};
};
// uses memoized version of makeChange and provides cache to that function;
// after cache has been populated, by executing memoized version of makeChange,
// find the option with smallest length and return it
const pickSubset = (toPay, options) => {
const cache = new Set();
const memoizedPickSubset = memoizeFirstTwoArgs(_pickSubset);
memoizedPickSubset(toPay, options, [], cache);
let minLength = Infinity;
let resValues;
for (const value of cache) {
if (value.length < minLength) {
minLength = value.length;
resValues = value;
}
}
return resValues;
}
const options = [50, 25, 10, 5, 2, 1];
const toPay = 73;
console.log(pickSubset(toPay, options));

How do I get Fibonacci numbers in an array?

Given input = [1,2,4] return [1,2], or if no fibonacci numbers return [], [1,1,2] should return [1,2];
I know you can check whether a number is in the fibonacci sequence with this code:
function isSquare(n) {
return n > 0 && Math.sqrt(n) % 1 === 0;
};
//Equation modified from http://www.geeksforgeeks.org/check-number-fibonacci-number/
function isFibonacci(numberToCheck)
{
// numberToCheck is Fibinacci if one of 5*n*n + 4 or 5*n*n - 4 or both
// is a perferct square
return isPerfectSquare(5*numberToCheck*numberToCheck + 4) ||
isPerfectSquare(5*numberToCheck*numberToCheck - 4);
}
But I don’t know how to implement it. Thanks.
Array.from(new Set(arr)) Removes duplicates from the original array
let newArr = []; Defining the new array
for ( let i = 0; i < arrD.length; i++ ) Loop every number of arrD, arrD[i] accesses a number in the array
if(fib(arrD[i])) { newArr.push(arrD[i]); } if the number is in the fibonacci sequence, fib(arrD[i]) will return true, and the number will be .pushed into the newArr
Using a for loop
let arr = [1,2,3,8,3,8];
let sqrt = (num) => { return num > 0 && Math.sqrt(num) % 1 === 0; };
let fib = (num) => { return sqrt(5 * Math.pow(num,2) + 4) || sqrt(5 * Math.pow(num,2) - 4); };
function fibArr(arr) {
arrD = Array.from(new Set(arr));
let newArr = [];
for ( let i = 0; i < arrD.length; i++ ) {
if(fib(arrD[i])) { newArr.push(arrD[i]); }
}
return newArr;
}
console.log(fibArr(arr));
OR using .filter
let arr = [1,2,3,8,3,8];
let sqrt = (num) => { return num > 0 && Math.sqrt(num) % 1 === 0; };
let fib = (num) => { return sqrt(5 * Math.pow(num,2) + 4) || sqrt(5 * Math.pow(num,2) - 4); };
function fibArr(arr) {
arrD = Array.from(new Set(arr));
let newArr = arrD.filter(function(arrD){
return fib(arrD);
})
return newArr;
}
console.log(fibArr(arr));

how to find mean and variance using reduce()?

I wrote a function which returns mean and variance of the given list using only reduce().
var list = [1, 2, 3, 4];
var math = getMeanAndVar(list);
function getMeanAndVar(list) {
var res = list.reduce(function(lis, cur, ind, arr) {
var meanTot = arr.reduce(function(pre, cur) {
return pre + cur;
})
var total = getVariance(arr, tot / arr.length);
return {
mean: meanTot / arr.length,
variance: total / arr.length
}
function getVariance(list, mean) {
return list.reduce(function(pre, cur) {
pre = pre + Math.pow((cur - mean), 2);
return pre;
}, 0)
}
})
return ["Mean:",
res.mean,
"Variance:",
res.variance
].join(' ');
}
console.log(math);
Is there any other way to optimize the code?
Get rid of the outer reduce. It is useless. consider this:
function getMeanAndVar(arr) {
function getVariance(arr, mean) {
return arr.reduce(function(pre, cur) {
pre = pre + Math.pow((cur - mean), 2);
return pre;
}, 0)
}
var meanTot = arr.reduce(function(pre, cur) {
return pre + cur;
})
var total = getVariance(arr, meanTot / arr.length);
var res = {
mean: meanTot / arr.length,
variance: total / arr.length
}
return ["Mean:",
res.mean,
"Variance:",
res.variance
].join(' ');
}
var arr = [1, 2, 3, 4];
var math = getMeanAndVar(arr);
console.log(math);'
Prints:
Mean: 2.5 Variance: 1.25

Categories