Reduce function to take an undefined initial value - javascript

I want to create a function (reduce) that does the following:
Where:
var collection = [1, 2, 3];
and
function iterator(total, element) {
return total + element;
};
if initial is defined as 3:
reduce(collection, iterator, 3)
will do this:
3 + 1
4 + 2
6 + 3 = 9
if initial is undefined:
reduce(collection, iterator)
will do this:
1 + 2
3 + 3 = 6
Here is my code:
var reduce = function(collection, iterator, initial) {
if (initial === undefined) {
var total = 0;
} else {
var total = initial;
}
each(collection, function(element) {
total = iterator(total, element);
});
return total;
}
It works, but you can see that I've hard-coded total = 0, but I want this code to work in other scenarios (for example, multiplication, where I wouldn't want 0 to make the whole product 0).

This is how I would implement it:
alert(reduce([1,2,3], add, 3)); // 9
alert(reduce([1,2,3], add)); // 6
function add(a, b) {
return a + b;
}
function reduce(array, iterator, initial) {
var length = array.length;
var index = 0;
if (arguments.length < 3) {
if (length > 0) var result = array[index++]; // Note 1
else throw new Error("Reduce of empty array with no initial value");
} else var result = initial;
while (index < length) result = iterator(result, array[index++]);
return result;
}
The code is pretty self explanatory. Nevertheless, here's how it works, if the number of arguments passed are less than 3 it means that initial was not given. Hence we set result to array[0] and increment index. If array is empty then we throw an error instead. Otherwise we set the result to the initial value passed to the function. Everything else works as normal.
Note 1: The reason we don't modify initial (i.e. write initial = array[index++]) is because if we use arguments in a function and also modify the parameters of the function then the function will not be optimized in V8. Hence, it will execute slower.
Hope this helps.

Related

Recursive approach to Persistent bugger problem returns undefined

I've been trying to solve the following problem in codewars using recursion:
Write a function, persistence, that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit.
For example (Input --> Output):
39 --> 3 (because 3*9 = 27, 2*7 = 14, 1*4 = 4 and 4 has only one digit)
999 --> 4 (because 9*9*9 = 729, 7*2*9 = 126, 1*2*6 = 12, and finally 1*2 = 2)
4 --> 0 (because 4 is already a one-digit number)
Here's what I've tried:
var numOfIterations = 0;
function persistence(num) {
//code me
var i;
var digits=[];
var result = 1;
if (num.toString().length==1) {
return numOfIterations;
} else {
numOfIterations++;
digits = Array.from(String(num), Number);
for (i=0;i<digits.size;i++) {
result=result*digits[i];
}
persistence(result);
}
}
But for some reason, instead of returning the number of iterations, it returns undefined. I've been told that I'm not using recursion correctly, but I just can't find the problem.
Other answers have explained what's wrong with your code. I just want to point out a simpler implementation:
const multiplyDigits = (n) =>
n < 10 ? n : (n % 10) * multiplyDigits (n / 10 | 0);
const persistence = (n) =>
n < 10 ? 0 : 1 + persistence (multiplyDigits (n));
[39, 999, 4] .forEach (t => console .log (`${t}:\t${persistence (t)}`));
multiplyDigits does just what it says, recursively multiplying the final digit by the number left when you remove that last digit (Think of | 0 as like Math .floor), and stopping when n is a single digit.
persistence checks to see if we're already a single digit, and if so, returns zero. If not, we add one to the value we get when we recur on the multiple of the digits.
I've been told that I'm not using recursion correctly
You're recursing, but you're not returning the result of that recursion. Imagine for a moment just this structure:
function someFunc() {
if (someCondition) {
return 1;
} else {
anotherFunc();
}
}
If someCondition is false, what does someFunc() return? Nothing. So it's result is undefined.
Regardless of any recursion, at its simplest if you want to return a result from a function then you need to return it:
function persistence(num) {
//...
if (num.toString().length==1) {
//...
} else {
//...
return persistence(result); // <--- here
}
}
As #David wrote in his answer, you were missing the return of the recursive call to itself.
Plus you were using digits.size instead of digits.length.
Anyway consider that one single digit being zero will collpse the game because that's enough to set the result to zero despite how many digits the number is made of.
To deal with the reset of numOfIterations, at first I tried using function.caller to discriminate between recursive call and direct call and set the variable accordingly. Since that method is deprecated as shown here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
I opted for the optional argument iteration that gets set to zero as default, to keep track of that value while it goes down the call stack. This solution still fulfills the fact that the caller doesn't need to know a new interface for the function to work.
//var numOfIterations = 0;
function persistence(num, iteration=0) {
/*
Commented strategy using the function.caller
working but deprecated so I can't recommend anymore
used optional argument iteration instead
//gets the name of the caller scope
let callerName = persistence.caller?.name;
//if it's different from the name of this function
if (callerName !== 'persistence')
//reset the numOfIterations
numOfIterations = 0;
*/
var digits=[];
if (num.toString().length==1){
return iteration;
} else {
var result = 1;
digits = Array.from(String(num), Number);
for (let i=0;i<digits.length;i++) {
result = result * digits[i];
}
return persistence(result, iteration+1);
}
}
console.log( persistence(39) ); //-> 3
console.log( persistence(999 ) ); //-> 4
console.log( persistence(4) ); //-> 0
You can do something like this
const persistenceTailRecursive = (num, iterations = 0) => {
const str = '' + num;
if(str.length === 1){
return iterations;
}
return persistenceTailRecursive(str.split('').reduce((res, a) => res * parseInt(a), 1), iterations + 1)
}
const persistence = (num) => {
const str = '' + num;
if(str.length === 1){
return 0;
}
return 1 + persistence(str.split('').reduce((res, a) => res * parseInt(a), 1))
}
console.log(persistenceTailRecursive(93))
console.log(persistenceTailRecursive(999))
console.log(persistence(93))
console.log(persistence(999))
There are 2 versions
1 tailRecursive call the same method with the exact signature (preventing stackoverflow in some languages like scala)
2 basic the result is calculated at the end

Multiplicative Persistence program in Javascript not working

I can't get my program to work. The problem is a kata from Codewars:
Write a function, persistence, that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit.
Example:
persistence(39) === 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
// and 4 has only one digit
persistence(999) === 4 // because 9*9*9 = 729, 7*2*9 = 126,
// 1*2*6 = 12, and finally 1*2 = 2
persistence(4) === 0 // because 4 is already a one-digit number
I've gone through answers to similar problems here already. This is my code:
var count = 0;
var product = 1;
function persistence(num) {
if (num.toString().length == 1) {
count+=0;
return count;
}
for (i of num.toString()) {
product *= Number(i);
}
count++;
var newProduct = product;
// reset product to 1 so that line ten does not
// start with the product from the last loop
product = 1;
persistence(newProduct);
}
I can't tell what the problem is. Initially I was getting a maximum call stack exceeded error. I researched that and realized I did this for my base case:
if (num.length == 1) {
count+=0;
return count;
}
instead of
if (num.toString().length == 1) {
count+=0;
return count;
}
My logic seems sound. What could the problem be?
Here's a much better way of solving your problem, complete with comments that I think gives a pretty clear explanation of what's going on.
function persistence(num) {
// Create a new function that you'll use inside your main function
function multiply(n) {
// Multiply the first number by next number in the array
// until the entire array has been iterated over
return n.reduce(function(a,b){return a*b;});
}
// Set the count to 0
var count =0;
// Use a while loop to iterate the same number of times
// as there are digits in num
while (num.toString().length > 1) {
// Splits the num into an array
num= num.toString().split("");
// Runs multiply on our num array and sets num to the returned
// value in preparation of the next loop.
// The multiply function will for 39 run 3 * 9 = 27,
// next iteration we've set num to 27 so multiply will be
// 2 * 7 = 14, then 1 * 4 = 4, and since num 4 now
// has a length <= 1 the loop stops.
num = multiply(num);
// Increase count by 1 each iteration, then run the next
// iteration in the loop with the new value for num being
// set to the result of the first multiplication.
count++;
}
return count; // return the value of count
}
console.log(persistence(39));// === 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
// and 4 has only one digit
console.log(persistence(999));// === 4 // because 9*9*9 = 729, 7*2*9 = 126,
// 1*2*6 = 12, and finally 1*2 = 2
console.log(persistence(4));// === 0 // because 4 is already a one-digit number
https://jsfiddle.net/8xmpnzng/
Use "of" instead of "in". "in" looks for properties. "of" increments an array.
var count = 0;
var product = 1;
function persistence(num) {
if (num.toString().length == 1) {
count+=0;
return count;
}
for (i of num.toString()) {
product *= Number(i);
}
count++;
var newProduct = product;
// reset product to 1 so that line ten does not
// start with the product from the last loop
product = 1;
persistence(newProduct);
}
I'm pretty sure it's this block:
for (i in num.toString()) {
product *= Number(i);
}
That's a for...in loop, which is used to iterate over keys in an object. If you want to multiply each digit of the num string together, you could split the string into an array, and use the reduce method (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce):
//this coerces the number into a string
const numString = num + ''
//this is the function to pass as the first argument into the reduce method
const multiplyAll = (accumulator, currentVal) => accumulator * Number(currentVal)
let product = numString.split('').reduce(multiplyAll, 1)
It's generally best practice to avoid declaring global variables outside of a function's scope, but you can do a cool trick with your recursion where you declare your count as a parameter in your function like so:
function persistence(num, count = 0) {
And then when you call it again with recursion, you simply add 1 like so:
function persistence(product, count + 1) {
Simpler way of Persistence:
let countIteration = 1;
function persistence(num) {
let numStr = num.toString();
if(numStr.toString().length === 1) {
return 0;
}
let numArr = numStr.split("");
let persistRes = numArr.reduce((acc, curr) => acc = curr * acc);
if (persistRes.toString().length !== 1) {
countIteration += 1;
return persistence(persistRes);
}
else {
return countIteration;
}
}
console.log(persistence(39)); // === 3
console.log(persistence(15)); // === 1
console.log(persistence(999));// === 4

Sum of range in Javascript in function local variable

I have range function and output functions they works correct,now I want create sum function for using as callbac function in range function,but when some function executed local variable let us say total or sum initialize 0(zero),how can solve this problem?
function range(start,end,callback,step) {
// body...
step=step || 1;
for(i=start;i<=end;i=i+step){
callback(i);
}
}
function output(a) {
// body...
console.log(a);
}
function sum(m){
var total=0;
// some code
}
range(1,5,output);
range(1,5,sum);
function range(start,end,callback,step) {
// body...
var aggregate;
step=step || 1;
for(i=start;i<=end;i=i+step){
aggregate = callback(i, aggregate);
}
}
function output(a) {
// body...
console.log(a);
}
function sum(m, aggregate){
return m + aggregate;
}
range(1,5,output);
range(1,5,sum);
This way you could even do cool stuff like
function conc(m, aggregate) {
return aggregate + m.toString();
}
range(1,5,conc,2); //prints 135
Continuition style code, like you've started it with range(), can get really weird and cumbersome.
And please, please, mind defining your local variables. like i
function range(start,end,callback,step) {
step=step || 1;
for(var i=start; i<=end; i=i+step)
callback(i);
}
function output(...label) {
return function(...args){
console.log(...label, ...args);
}
}
function sum(callback){
var total = 0;
return function(value){
//will log ever intermediate total, because sum() has no way to tell when the sequence is over.
callback(total += +value || 0);
}
}
range(1,5,output('range:'));
range(1,5,sum(output('sum:')));
In this case, I'd prefer using a generator instead, although the higher order functions get obsolete.
function *range(start,end,step) {
step = +step || (end < start? -1: 1);
for(var value = start, count = (end - start) / step; count-- >= 0; value += step)
yield value
}
function sum(iterator){
var total = 0, v;
for(v of iterator) total += +v || 0;
return total;
}
console.log("range:", ...range(1,5))
console.log("sum of range:", sum(range(1,5)))
//just to show that this works with your regular array as well
console.log("sum of array:", sum([1,2,3,4,5]));
//and some candy, as requested by Bergi ;)
//I like to stay with the interfaces as close as possible to the native ones
//in this case Array#reduce
var fold = (iterator, callback, start = undefined) => {
var initialized = start !== undefined,
acc = start,
index = 0,
value;
for(value of iterator){
acc = initialized?
callback(acc, value, index):
(initialized=true, value);
++index;
}
if(!initialized){
throw new TypeError("fold of empty sequence with no initial value");
}
return acc;
}
//and the ability to compose utility-functions
fold.map = (callback, start = undefined) => iterator => fold(iterator, callback, start);
console.log(" ");
var add = (a,b) => a + b; //a little helper
console.log('using fold:', fold(range(1,5), add, 0));
//a composed utility-function
var sum2 = fold.map(add, 0);
console.log('sum2:', sum2( range(1,5) ));
Clearly a range function should not take a callback but be a generator function in modern JavaScript, however you were asking how to write such a callback.
You've already tagged your questions with closures, and they are indeed the way to go here. By initialising a new total within each call of the outer function, you don't need to worry about how to reset a global counter.
function makeSum() {
var total=0;
return function(m) {
total += m;
return total; // so that we can access the result
}
}
var sum = makeSum();
range(1, 5, sum);
output(sum(0));
Won't simply calling the callback on the range array suffice if the callback is not undefined? Like this:
> function range(n, callback) {
const r = [...Array(n).keys()]
if (callback) {
return callback(r)
}
return r
}
> function sum(arr) {
return arr.reduce((a, b) => a + b, 0)
}
> range(10)
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
> range(10, sum)
> 45

what does a recursive closure returns to?

I want to write a function (persistence) that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit.
For example:
persistence(39) === 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
// and 4 has only one digit
persistence(999) === 4 // because 9*9*9 = 729, 7*2*9 = 126,
// 1*2*6 = 12, and finally 1*2 = 2
persistence(4) === 0 // because 4 is already a one-digit number
I wrote this:
function persistence(num) {
//code me
var f;
f= countPersistence(num);
var toReturn= f(num); console.log("received value: "+toReturn);
return toReturn;
}
function countPersistence(num){
var count=0;
return function g(num){
var numt=num+"";
numt=numt.split("");
if(numt.length>1){
count++;
for(var i=0; i<numt.length-1; i++){
numt[i+1]=numt[i]*numt[i+1];
}
arguments.callee(numt[numt.length-1]);
}
else
{ console.log("returned value: "+count); return count;}
}
}
As you can see running this code, the returned value of the inner function is not exactly what expected.
Indeed, a function should return to where it is called from, right?. But in this case since it's recursive it is called from itself.
I have no idea how to retrieve the actual value (without using global variable)
You do not return a value when you call your inner function recursively. You could fix it like this (removing the else block and making it common code), so that always the last updated value of count is returned:
function persistence(num) {
//code me
var f;
f= countPersistence(num);
var toReturn= f(num);
return toReturn;
}
function countPersistence(num){
var count=0;
return function g(num){
var numt=num+"";
numt=numt.split("");
if(numt.length>1){
count++;
for(var i=0; i<numt.length-1; i++){
numt[i+1]=numt[i]*numt[i+1];
}
arguments.callee(numt[numt.length-1]);
}
return count;
}
}
console.log(persistence(39)); // 3
console.log(persistence(999)); // 4
console.log(persistence(4)); // 0
But arguments.callee is deprecated, and moreover you are making things overly complicated with nested functions.
You can do it like this:
function persistence(num){
return num < 10 ? 0
: 1 + persistence(String(num).split('').reduce((a, b) => a*b));
}
console.log(persistence(39)); // 3
console.log(persistence(999)); // 4
console.log(persistence(4)); // 0
You are not returning on the recursion line
return arguments.callee(numt[numt.length-1]);
and as I stated in the comments arguments.callee is deprecated so you should use the function name.
return g(numt[numt.length-1]);

How to add up numbers in a nested array javascript

Just working on a project and tried a few different solutions but with no results. Could someone help me with how to add up numbers in a nested array? Would I use reduce? or a for loop?
function balance(arr) {
if(typeof item == 'number') {
return arr;enter code here
} else {
return arr + balance(item);
}
}
Is this maybe what you are hoping for?
function balance(arr) {
return arr.reduce(function(sum, item) {
if(typeof item == 'number') {
return sum;
} else {
return sum + balance(item);
}
},0);
}
console.log(balance([1,2,[3,4],5]));
Just for the record (to disprove the assertion that recursion is required), here's a version that uses a sequential algorithm. Recursion is concise and (usually) easier to read, however if speed matters, it can be slow. However, based on results from jsPerf, script engines seem very much better at optimising recursive code than they used to be, at least for simple programs like this.
For comparison, I've included a recursive version using a plain loop, the jsPerf tests also include a (fixed) recursive version using reduce. I suspect Any's answer will be slowest as it calls slice and itself on every loop, but I didn't have time to fix it.
So I guess recursion is fine here as it is fast and concise.
/* Sum the values of nested arrays. Only checks if values are arrays,
** otherwise assumes they're numbers
**
** #param {Array} arr - array of numbers to process, may have
** nested arrays of numbers
** #returns {number} - sum of values or NaN if arr is not an Array
*/
function balance(arr) {
// Only process arrays
var isArray = Array.isArray;
if (!isArray(arr)) return NaN;
// Setup
var arrays = [], indexes = [];
var currentArray = arr;
var currentValue;
var sum = 0;
var i = 0, iLen = arr.length;
// Use <= length as must handle end of array inside loop
while (i <= iLen || arrays.length) {
currentValue = currentArray[i];
// If at end of current array, reset value to before entering array
// Reset i to previous value as will increment at the bottom
if (i == currentArray.length && arrays.length) {
currentArray = arrays.pop();
i = indexes.pop();
iLen = currentArray.length;
// If current value is an array, use it and reset loop control values
// set i to -1 as will increment at the bottom
} else if (isArray(currentValue)) {
arrays.push(currentArray);
indexes.push(i);
currentArray = currentValue;
i = -1;
iLen = currentArray.length;
// Otherwise, add the current value
// Will be undefined if at end of array so add zero
} else {
sum += +currentValue || 0;
}
// Increment i
i++;
}
return sum;
}
document.write(
'balance sequential 1: ' +
balance([1,[2,1,[1,2,-1],[1]],1,[2,1]]) // 11
+ '<br>balance sequential 2: ' +
balance([1,2,[3,4],5]) // 15
);
/* Sum the values of nested arrays. Only checks if values are arrays,
** otherwise assumes they're numbers
**
** #param {Array} arr - array of numbers to process, may have
** nested arrays of numbers
** #returns {number} - sum of values or NaN if arr is not an Array
*/
function balanceLoop(arr) {
if (!Array.isArray(arr)) return NaN;
for (var value, total=0, i=0, iLen=arr.length; i<iLen; i++) {
value = arr[i];
total += Array.isArray(value)? balanceLoop(value) : value;
}
return total;
}
document.write(
'<br>balanceLoop 1: ' +
balanceLoop([1,[2,1,[1,2,-1],[1]],1,[2,1]]) // 11
+ '<br>balanceLoop 2: ' +
balanceLoop([1,2,[3,4],5]) // 15
);
A simple recursive function:
function balance(arr, total) {
total = total || 0;
if (arr.length === 0) return total;
var head = arr[0];
if (typeof head === 'number') {
return balance(arr.slice(1), total += head);
} else {
return balance(head, total);
}
}
balance([1, [2, 1, 3, [43, 2]]])); // 52
DEMO
I would probably solve this using a recursive reduce, in the following manner:
function balance(arr) {
return arr.reduce(function(sum,item) {
return sum + (item instanceof Array ? balance(item) : item);
}, 0);
};
balance([1,[2,1,[1,2,-1],[1]],1,[2,1]]); // 11
If you don't mind the overhead, you could of course do this:
Number.prototype.balance = function() { return this; };
Array.prototype.balance = function() { return this.reduce(function(a,b) { return a + b.balance(); }, 0); }
[1,[2,1,[1,2,-1],[1]],1,[2,1]].balance(); // 11

Categories

Resources