## Trampoline recursion stack overflow - javascript

### Calculating second largest number in array (Javascript) : Seems to work in Sandbox but fails Hackerrank testing

```Tried to determine the second largest number in an array (Javascript) on CodeSandbox. It seems to work fine, but it fails the CodeWars testing. I have added a dummy array just to run my own tests in Sandbox.(Have mercy, I'm a beginner and this is my first StackOverFlow question)
const nums = [3, 100.3, 88, 1, -2.4, 9, 18];
const getSecondLargest = (nums) => {
const descending = nums.sort((a, b) => b - a);
return descending[1];
};
console.log(getSecondLargest(nums)); // console returns 88
EDIT: Okay so I with my super-tired brain I said CodeWars, when I actually meant Hackerrank (so sorry!). I realized they didn't necessarily test with NaNs, but they did have repeating numbers, so using the index of [1] isn't ideal. The exercise is from the 10 Days of Javascript - Day 3: Arrays https://hackerrank.com/domains/tutorials/10-days-of-javascript
So I now tried this code below, and it passes...but my code seems a bit janky, is there a cleaner way to write this, and can I combine it with the isNan logic then?
const nums = [3, 100, 88, 100, -2.4, 9, 18];
const getSecondLargest = (nums) => {
const ascending = nums.sort((a, b) => a - b);
if (ascending[ascending.length - 2] === ascending[ascending.length - 1]) {
return ascending[ascending.length - 3];
} else {
return ascending[ascending.length - 2];
}
};
console.log(getSecondLargest(nums)); // console returns 88
```
```It looks like there maybe strings in the array and you need to handle that. Here are a few ways:
One is to filter the non-numerical stuff out before sorting. You can use isNaN() to test if an object "is not a number".
const getSecondLargest = (nums) => {
const descending = nums
.filter(n => !isNaN(n))
.sort((a, b) => b - a);
return descending.length < 2 ? undefined : descending[1];
};
Another option is to handle the strings in sorting. Push them to the end of the array:
const getSecondLargest = (nums) => {
const descending = nums.sort((a, b) => {
if (isNaN(a) && isNaN(b)) return 0;
if (isNaN(a)) return 1;
if (isNaN(b)) return -1;
return b - a;
});
return descending.length < 2 || isNaN(descending[1]) ? undefined : descending[1];
};
A third way is a simple for loop that keeps track of the 2 highest values:
const getSecondLargest = (nums) => {
let max1 = undefined;
let max2 = undefined;
for (let n of nums) {
if (isNaN(n)) continue;
if (max2 === undefined || n > max2) {
if (max1 === undefined || n > max1 ) {
max2 = max1;
max1 = n;
}
else {
max2 = n;
}
}
}
return max2;
}```

### Chain methods and call function one by one

```so basically I need to implement a lazy evaluation. .add() takes a function as parameter and any other arbitrary arguments. The function that is passed as an argument is run later (when evaluate is called) with other arguments(if any) as parameters to that function.
Basically my issue stands when i run .evaluate() which takes an array as parameter, the functions that were passed to add() as parameters are not called one at a time and returning a result and have it as a parameter for the next.
class Lazy {
constructor() {
this.functions = [];
this.counter = 0;
this.resultedArray = [];
}
if (args.length > 0) {
this.counter++;
const argsArrayNumeric = args.filter((item) => typeof item === "number");
this.functions.push({
func: func,
args: args,
});
} else {
if (func.length <= args.length + 1 || func.length === args.length) {
this.counter++;
this.functions.push({ func: func });
} else {
console.log("Missing parameters for " + func.name + " function");
}
}
return this;
}
evaluate(array) {
if (this.counter > 0) {
let result;
this.functions.map((obj, index) => {
array.map((item, index) => {
console.log(obj);
if (obj.func && obj.args) {
result = obj.func(item, ...obj.args);
} else {
result = obj.func(item);
}
this.resultedArray.push(result);
});
});
console.log(this.resultedArray);
} else {
console.log(array);
}
}
}
const s = new Lazy();
const timesTwo = (a) => {
return a * 2;
};
const plus = (a, b) => {
return a + b;
};
//correct result is [3,5,7] but i have [ 2, 4, 6, 2, 3, 4 ]
```
```There are a few problems in evaluate:
push will be executed too many times when you have more than one function.
Don't use map when you don't really map. .map() returns a result.
From the expected output (in the original version of the question) it seems you need to apply the functions from right to left, not from left to right.
this.counter does not really play a role. The length of the this.functions array should be all you need.
the result should not be printed in the method, but returned. It is the caller's responsibility to print it or do something else with it.
All this can be dealt with using reduce or reduceRight (depending on the expected order) like this:
evaluate(array) {
return this.functions.reduceRight((result, obj) =>
result.map((item) => obj.func(item, ...(obj.args || [])))
, array);
}
And in the main program, print the return value:
The add method has also some strange logic, like:
When the first if condition is false, then the else block kicks in with args.length == 0. It is then strange to see conditions on args.length... it really is 0!
If the first condition in func.length <= args.length + 1 || func.length === args.length is false, then surely the second will always be false also. It should not need to be there.
argsArrayNumeric is never used.
All in all, it seems the code could be reduced to this snippet:
class Lazy {
constructor() {
this.functions = [];
}
if (func.length > args.length + 1) {
throw ValueError(`Missing parameters for \${func.name} function`);
}
this.functions.push({ func, args });
return this;
}
evaluate(array) {
return this.functions.reduceRight((result, obj) =>
result.map((item) => obj.func(item, ...(obj.args || [])))
, array);
}
}
const timesTwo = (a) => a * 2;
const plus = (a, b) => a + b;
const s = new Lazy();
```
```I think you're working too hard at this. I believe this does almost the same thing (except it doesn't report arity errors; that's easy enough to include but doesn't add anything to the discussion):
class Lazy {
constructor () {
this .fns = []
}
this .fns .push ({fn, args});
return this
}
evaluate (xs) {
return xs .map (
x => this .fns .reduce ((a, {fn, args}) => fn (...args, a), x)
)
}
}
const timesTwo = (a) => a * 2
const plus = (a, b) => a + b
console .log (s .evaluate ([1, 2, 3]))
But I don't actually see much of a reason for the class here. A plain function will do much the same:
const lazy = (fns = [], laze = {
add: (fn, ...args) => lazy (fns .concat ({fn, args})),
evaluate: (xs) => xs .map (
x => fns .reduce ((a, {fn, args}) => fn (...args, a), x)
)
}) => laze
const timesTwo = (a) => a * 2
const plus = (a, b) => a + b
console .log (s .evaluate ([1, 2, 3]))
This is slightly different in that s is not mutated on each add, but a new object is returned. While we could change that and mutate and return the original object easily enough, the functional programming purist in me would actually consider moving more in that direction. In fact, all we're maintaining here is a list of {fn, args} objects. It might make the most sense to take that on directly, like this:
const add = (lazy, fn, ...args) => lazy .concat ({fn, args})
const evaluate = (lazy, xs) => xs .map (
x => lazy .reduce ((a, {fn, args}) => fn (...args, a), x)
)
const timesTwo = (a) => a * 2
const plus = (a, b) => a + b
const q = []
const r = add (q, timesTwo)
const s = add (r, plus, 1)
// or just
console .log (evaluate (s, [1, 2, 3]))
In this version, we don't need a Lazy constructor or a lazy factory function, as our data structure is a plain array. While this is the format I prefer, any of these should do something similar to what you're trying.
Update
Based on comments, I include one more step on my journey, between the first and second snippets above:
const lazy = () => {
const fns = []
const laze = {
add: (fn, ...args) => fns .push ({fn, args}) && laze,
evaluate: (xs) => xs .map (
x => fns .reduce((a, {fn, args}) => fn (...args, a), x)
)
}
return laze
}
const timesTwo = (a) => a * 2
const plus = (a, b) => a + b
console .log (s .evaluate ([1, 2, 3]))
This version may be more familiar than the second snippet. It stores fns in a closure, hiding implementation details in a way we often don't with JS classes. But that list is still mutable through the add method of the object we return. Further ones proceed down the road to immutability.```

### Javascript - Counting array elements by reduce method until specific value occurs doesn't give a correct output

```const arr = [5,6,0,7,8];
const sum = (arr,num) => arr.reduce((total)=>(num==0 ? total : total+num), 0)
console.log(sum(arr, 0))
Please check how can I make it work. Did some mistake but don't know what exactly. Output is a function instead of a result.
```
```This is awkward to do in .reduce because it goes through the entire array. If we do a naive implementation you can see the problem:
const arr = [5,6,0,7,8];
const sum = (arr,num) => arr.reduce((total, x)=>(num==x ? total : total+x), 0)
console.log(sum(arr, 0))
We now make the check correctly - num==x will return true when x is zero (the value of num). However, the result is wrong because this only returns true once but any other iteration it's still true. And here is the same thing with more logging that describes each step of the process:
const arr = [5,6,0,7,8];
const sum = (arr,num) => arr.reduce((total, x)=> {
const boolCheck = num==x;
const result = boolCheck ? total : total+x;
console.log(
`total: \${total}
num: \${num}
x: \${x}
boolCheck: \${boolCheck}
result: \${result}`);
return result;
}, 0)
console.log(sum(arr, 0))
So, you need to add some flag that persists between iterations, so it doesn't get lost.
One option is to have an external flag that you change within the reduce callback:
const arr = [5,6,0,7,8];
const sum = (arr,num) => {
let finished = false;
return arr.reduce((total, x) => {
if(x === num)
finished = true;
return finished ? total : total+x;
}, 0)
}
console.log(sum(arr, 0))
Alternatively, you can have that flag internal to the reduce callback and pass it around between calls. It works the same way in the end but makes the callback function pure. At the cost of some unorthodox construct:
const arr = [5,6,0,7,8];
const sum = (arr,num) => {
return arr.reduce(({total, finished}, x) => {
if(x === num)
finished = true;
total = finished ? total : total+x;
return {total, finished};
}, {total: 0, finished: false})
.total
}
console.log(sum(arr, 0))
If you want to use reduce but you're OK with using other methods, then you can use Array#indexOf to find the first instance of a value and Array#slice the array that contains any value up to the target value:
const arr = [5,6,0,7,8];
const sum = (arr,num) => {
const endIndex = arr.indexOf(num);
return arr.slice(0, endIndex)
.reduce((total, x)=> total+x, 0)
}
console.log(sum(arr, 0))
Or in as one chained expression:
const arr = [5,6,0,7,8];
const sum = (arr,num) => arr
.slice(0, arr.indexOf(num))
.reduce((total, x)=> total+x, 0);
console.log(sum(arr, 0))
Other libraries may have a takeUntil or takeWhile operation which is even closer to what you want - it gets you an array from the beginning up to a given value or condition. You can then reduce the result of that.
Here is an example of this using Lodash#takeWhile
By using chaining here, Lodash will do lazy evaluation, so it will only go through the array once, instead of scanning once to find the end index and going through the array again to sum it.
const arr = [5,6,0,7,8];
const sum = (arr,num) => _(arr)
.takeWhile(x => x !== num)
.reduce((total, x)=>total+x, 0)
console.log(sum(arr, 0))
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>
As a note, if you are using Lodash, then you may as well use _.sum(). I didn't above just to illustrate how a generic takeUntil/takeWhile looks.
const arr = [5, 6, 0, 7, 8];
const sum = (arr, num) => _(arr)
.takeWhile(x => x !== num)
.sum()
console.log(sum(arr, 0))
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>
```
```Since you need to stop summing values part way through the array, this might be most simply implemented using a for loop:
const arr = [5, 6, 0, 7, 8];
const num = 0;
let sum = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i] == num) break;
sum += arr[i];
}
console.log(sum);
If you want to use reduce, you need to keep a flag that says whether you have seen the num value so you can stop adding values from the array:
const arr = [5, 6, 0, 7, 8];
const sum = (arr, num) => {
let seen = false;
return arr.reduce((c, v) => {
if (seen || v == num) {
seen = true;
return c;
}
return c + v;
}, 0);
}
console.log(sum(arr, 0));
console.log(sum(arr, 8));
```
```call it as follows:
console.log(sum(arr, 0)());
```
```You need parenthesis to execute the function ()
sum(arr, 0)
Without parenthesis you store a reference to the function in the variable```

### Usage of Promise.All in recursion doesn't seems to be working

```Actual doSomething function posts ele to a remote API to do some calculations.
My calc function supposed to get the summation of the remote API's calculation for each element, It should run for every element without affecting how nested they are located.
However, Currently, I can't get this to work. How do I fix this?
const doSomething = (ele) => new Promise(resolve => {
console.log(ele);
resolve(ele * 2);//for example
})
const calc = (arr) => new Promise(
async(resolve) => {
console.log(arr.filter(ele => !Array.isArray(ele)));
let sum = 0;
const out = await Promise.all(arr.filter(ele => !Array.isArray(ele))
.map(ele => doSomething(ele)));
sum += out.reduce((a, b) => a + b, 0);
const out2 = await Promise.all(arr.filter(ele => Array.isArray(ele))
.map(ele => calc(ele)));
sum += out2.reduce((a, b) => a + b, 0);
resolve(sum);
}
)
const process = async () => {
console.log('processing..');
const arr = [1, 2, 3, 4, 5, [6,7], 1, [8,[10,11]]];
const out = await calc(arr);
console.log(out);
}
process();
```
```While it may look like I've addressed issues that are non-existent - the original code in the question had ALL the flaws I address in this answer, including Second and Third below
yes, the code in the question now works! But it clearly was flawed
First: no need for Promise constructor in calc function, since you use Promise.all which returns a promise, if you make calc async, just use await
Second: dosomething !== doSomething
Third: out2 is an array, so sum += out2 is going to mess you up
Fourth: .map(ele => doSomething(ele)) can be written .map(doSoemthing) - and the same for the calc(ele) map
So, working code becomes:
const doSomething = (ele) => new Promise(resolve => {
resolve(ele * 2); //for example
})
const calc = async(arr) => {
const out = await Promise.all(arr.filter(ele => !Array.isArray(ele)).map(doSomething));
let sum = out.reduce((a, b) => a + b, 0);
const out2 = await Promise.all(arr.filter(ele => Array.isArray(ele)).map(calc));
sum += out2.reduce((a, b) => a + b, 0);
return sum;
}
const process = async() => {
console.log('processing..');
const arr = [1, 2, 3, 4, 5, [6, 7], 1, [8, [10, 11]]];
const out = await calc(arr);
console.log(out);
}
process();
```
```Can I suggest a slightly different breakdown of the problem?
We can write one function that recursively applies your function to all (nested) elements of your array, and another to recursively total the results.
Then we await the result of the first call and pass it to the second.
I think these functions are simpler, and they are also reusable.
const doSomething = async (ele) => new Promise(resolve => {
setTimeout(() => resolve(ele * 2), 1000);
})
const recursiveCall = async (proc, arr) =>
Promise .all (arr .map (ele =>
Array .isArray (ele) ? recursiveCall (proc, ele) : proc (ele)
))
ns .reduce ((total, n) => total + (Array .isArray (n) ? recursiveAdd (n) : n), 0)
const process = async() => {
console.log('processing..');
const arr = [1, 2, 3, 4, 5, [6, 7], 1, [8, [10, 11]]];
const processedArr = await recursiveCall (doSomething, arr);
console.log(out);
}
process();
```
```I think a generic deepReduce solves this problem well. Notice it's written in synchronous form -
const deepReduce = (f, init = null, xs = []) =>
xs.reduce
( (r, x) =>
Array.isArray(x)
? deepReduce(f, r, x)
: f(r, x)
, init
)
Still, we can use deepReduce asynchronously by initialising with a promise and reducing with an async function -
deepReduce
( async (r, x) =>
await r + await doSomething(x)
, Promise.resolve(0)
, input
)
.then(console.log, console.error)
See the code in action here -
const deepReduce = (f, init = null, xs = []) =>
xs.reduce
( (r, x) =>
Array.isArray(x)
? deepReduce(f, r, x)
: f(r, x)
, init
)
const doSomething = x =>
new Promise(r => setTimeout(r, 200, x * 2))
const input =
[1, 2, 3, 4, 5, [6,7], 1, [8,[10,11]]]
deepReduce
( async (r, x) =>
await r + await doSomething(x)
, Promise.resolve(0)
, input
)
.then(console.log, console.error)
// 2 + 4 + 6 + 8 + (10 + 14) + 2 + (16 + (20 + 22))
// => 116
further generalisation
Above we are hand-encoding a summing function, (+), with the empty sum 0. In reality, this function could be more complex and maybe we want a more general pattern so we can construct our program piecewise. Below we take synchronous add and convert it to an asynchronous function using liftAsync2(add) -
const add = (x = 0, y = 0) =>
x + y // <-- synchronous
const main =
pipe
( deepMap(doSomething) // <-- first do something for every item
, deepReduce(liftAsync2(add), Promise.resolve(0)) // <-- then reduce
)
main([1, 2, 3, 4, 5, [6,7], 1, [8,[10,11]]])
.then(console.log, console.error)
// 2 + 4 + 6 + 8 + (10 + 14) + 2 + (16 + (20 + 22))
// => 116
deepMap and deepReduce generics. These are in curried form so they can plug directly into pipe, but that is only a matter of style -
const deepReduce = (f = identity, init = null) => (xs = []) =>
xs.reduce
( (r, x) =>
Array.isArray(x)
? deepReduce(f, r)(x)
: f(r, x)
, init
)
const deepMap = (f = identity) => (xs = []) =>
xs.map
( x =>
Array.isArray(x)
? deepMap(f)(x)
: f(x)
)
liftAsync2 takes a common binary (has two parameters) function and "lifts" it into the asynchronous context. pipe and identity are commonly available in most functional libs or easy to write yourself -
const identity = x =>
x
const pipe = (...fs) =>
x => fs.reduce((r, f) => f(r), x)
const liftAsync2 = f =>
async (x, y) => f (await x, await y)
Here's all of the code in a demo you can run yourself. Notice because deepMap synchronously applies doSomething to all nested elements, all promises are run in parallel. This is in direct contrast to the serial behaviour in the first program. This may or may not be desirable so it's important to understand the difference in how these run -
const identity = x =>
x
const pipe = (...fs) =>
x => fs.reduce((r, f) => f(r), x)
const liftAsync2 = f =>
async (x, y) => f (await x, await y)
const deepReduce = (f = identity, init = null) => (xs = []) =>
xs.reduce
( (r, x) =>
Array.isArray(x)
? deepReduce(f, r)(x)
: f(r, x)
, init
)
const deepMap = (f = identity) => (xs = []) =>
xs.map
( x =>
Array.isArray(x)
? deepMap(f)(x)
: f(x)
)
const doSomething = x =>
new Promise(r => setTimeout(r, 200, x * 2))
(x, y) => x + y
const main =
pipe
( deepMap(doSomething)
)
main([1, 2, 3, 4, 5, [6,7], 1, [8,[10,11]]])
.then(console.log, console.error)
// 2 + 4 + 6 + 8 + (10 + 14) + 2 + (16 + (20 + 22))
// => 116

### Can we implement tail recursion modulo cons et al. through trampolines?

```You can regard trampolines as compiler optimizations reified in the program. So what is stopping us from adapting more general optimization techniques in exactly the same manner.
Here is a sketch of tail recursion modulo cons:
const loop = f => {
let step = f();
while (step && step[step.length - 1] && step[step.length - 1].type === recur) {
let step_ = step.pop();
step.push(...f(...step_.args));
}
return step;
};
const recur = (...args) =>
({type: recur, args});
const push = (xs, x) => (xs.push(x), xs);
const map = f => xs =>
loop((i = 0) =>
i === xs.length
? []
: push([f(xs[i])], recur(i + 1)));
const xs =
map(x => x * 2) (Array(1e6).fill(0).map((x, i) => i))
.slice(0,5);
console.log(xs); // [0, 2, 4, 6, 8]
This kind of optimization depends on the associativity property of an expression. Multiplication is associative too and hence there is tail recursion modulo multiplication. However, I have to cheat to implement it in Javascript:
const loop = f => {
let step = f();
const acc = [];
while (step && step[1] && step[1].type === recur) {
acc.push(step[0]);
step = f(...step[1].args);
}
return acc.reduce((acc, f) => f(acc), step);
};
const recur = (...args) =>
({type: recur, args});
const mul = x => step => [y => x * y, step];
const pow = (x_, n_) =>
loop((x = x_, n = n_) =>
n === 0 ? 1
: n === 1 ? x
: mul(x) (recur(x, n - 1)));
console.log(
pow(2, 1e6)); // Infinity, no stack overflow
As you can see I cannot use a regular mul, which isn't particular satisfying. Is this connected with Javascript beeing a strict language? Is there a better way to achieve tail recursion modulo multiplication in JS without having to introduce awkward binary operators?
```
```Instead of using loop/recur (which I consider an ugly and unnecessary hack), consider using folds:
const recNat = (zero, succ) => n => {
let result = zero;
while (n > 0) {
result = succ(result);
n = n - 1;
}
return result;
};
const mul = x => y => x * y;
const pow = x => recNat(1, mul(x));
console.log([0,1,2,3,4,5,6,1e6].map(pow(2))); // [1,2,4,8,16,32,64,Infinity]
Almost every recursive function can be defined using folds (a.k.a. structural recursion, a.k.a. induction). For example, even the Ackermann function can be defined using folds:
const recNat = (zero, succ) => n => {
let result = zero;
while (n > 0) {
result = succ(result);
n = n - 1;
}
return result;
};
const add = x => y => x + y;
ackPredM => recNat(ackPredM(1),
ackMPredN => ackPredM(ackMPredN)));
console.time("ack(4)(1)");
console.log(ack(4)(1)); // 65533
console.timeEnd("ack(4)(1)");
The above code snippet takes about 18 seconds to compute the answer on my laptop.
Now, you might ask why I implemented recNat using iteration instead of natural recursion:
const recNat = (zero, succ) => function recNatZS(n) {
return n <= 0 ? zero : succ(recNatZS(n - 1));
};
I used iteration for the same reason you used iteration to implement loop. Trampolining. By implementing a different trampoline for every data type you're going to fold, you can write functional code without having to worry about stack overflows.
Bottom line: Use folds instead of explicit recursion. They are a lot more powerful than you think.```