recursing implementation function reduce javascript - javascript

I want to write a recursive version of reduce function.
Array.prototype.reduce2 =
function reduce(fn, initial) {
var head = this[0];
var tail = this.slice(1);
var result = fn(initial, head, 0, tail);
return reduce(tail, fn, result);
}
var a = [1, 2, 3, 4];
function add(a, b) { return a + b } ;
function mul(a, b) { return a * b } ;
function foo(a, b) { return a.concat(b) };
console.log(a.reduce(add), a.reduce2(add)); // 10 10
console.log(a.reduce(add, 10), a.reduce2(add, 10)) ; // 20 20
console.log(a.reduce(add, undefined), a.reduce2(add, undefined)); // NaN NaN
console.log(a.reduce(mul), a.reduce2(mul)); // 24 24
console.log(a.reduce(foo, ''), a.reduce2(foo, '')); // 1234 123
The result was:
10 [Function: add]
20 [Function: add]
NaN [Function: add]
24 [Function: mul]
1234 function foo(a, b) { return a.concat(b) }
Yes, I know that this seems like a lot of topics, but I couldn't find answer.

You should avoid adding methods to native objects.
You can do the same with a simple function in a simpler way using destructuring of the arguments.
function reduce(fn, initial, [head, ...tail]) {
return tail.length
? reduce(fn, fn(initial, head), tail)
: fn(initial, head)
}
Array.prototype.reduce2 = function(fn, initial) {
const head = this[0]
const tail = Array.prototype.slice.call(this, 1)
return tail.length
? tail.reduce2(fn, fn(initial, head))
: fn(initial, head)
}
const a = [1, 2, 3, 4];
const add = (a, b) => a + b
const mul = (a, b) => a * b
const foo = (a, b) => a.concat(b)
console.log(
reduce(add, 0, a),
a.reduce(add, 0),
a.reduce2(add, 0)
)
console.log(
reduce(mul, 1, a),
a.reduce(mul, 1),
a.reduce2(mul, 1)
)
console.log(
reduce(foo, '', a),
a.reduce(foo, ''),
a.reduce2(foo, '')
)
console.assert(
a.reduce2(add, 0) === 10,
'reduce2 can sum numbers'
)
console.assert(
a.reduce2(mul, 1) === 24,
'reduce2 can multiply numbers'
)
console.assert(
a.reduce2(foo, '') === '1234',
'reduce2 can contatinate strings'
)
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js?tab=assert"></script>

Related

Trouble simplifying conditional

I'm having trouble simplifying a conditional statement. It looks like this:
There is an array of arrays like this, dice = [ [a, b], [c, d] ].
a, b, c, and d representing random numbers on a dice 1 > 6.
Every array in the array represents a roll of two dice where the last roll is [c, d] = [2, 5] for example, and the second-last roll is [a, b] = [3, 6] for example.
Now if you roll 2 x 1 in a row or 2 x 6 in a row something happens.
so, a + c || a + d and b + c || b + d may not be 2 or 12.
The conditional below works but I think if you open the door to hell it looks prettier.
dice = last roll = [c, d]
prev = second last roll = [a, b]
if (dice[0] + prev[0] === 2 || dice[1] + prev[1] === 2 || dice[1] + prev[0] === 2 || dice[0] +
prev[1] === 2 &&
dice[0] + prev[0] === 12 || dice[1] + prev[1] === 12 || dice[1] + prev[0] === 12 || dice[0] +
prev[1] === 12){
//something happens here
}
I would do something like this:
var combinations = dice.reduce(function(acc, curr) {
return acc.concat(prev.map(function(curr2) {
return curr + curr2;
}));
}, []);
if (combinations.indexOf(2) !== -1 && combinations.indexOf(12) !== -1) {
//something happens here
}
In ES6 it is a little bit shorter:
const combinations = dice.reduce((acc, curr) => acc.concat(prev.map(curr2 => curr + curr2)), []);
if (combinations.indexOf(2) !== -1 && combinations.indexOf(12) !== -1) {
//something happens here
}
What this actually does is calculate all combinations (additions) and then check whether one is 2 and one is 12.
The condition can only happens when both dice and prev contain 1 or 6. So, we can just check that.
let throws = [[5,3],[1,6]];
let prev = throws[0];
let dice = throws[1];
if ((prev.includes(1) && dice.includes(1)) || (prev.includes(6) && dice.includes(6))){
console.log("2 or 12 occurs")
}
else {
console.log("2 and 12 do not occur")
}
What about something like the following?:
const one_and_six_found = (roll) => roll.includes(1) && roll.includes(6);
const two_rolls_have_one_and_six = (roll1, roll2) =>
one_and_six_found(roll1) && one_and_six_found(roll2);
console.log(two_rolls_have_one_and_six( [1, 6], [1, 6] ));
console.log(two_rolls_have_one_and_six( [6, 1], [1, 6] ));
console.log(two_rolls_have_one_and_six( [5, 1], [1, 6] ));
I came out with a simpler solution more fitted to your need
const throws1 = [[1, 2], [3, 4]]
const throws2 = [[1, 2], [3, 1]]
const throws3 = [[1, 6], [6, 1]]
const checkCondition = (prev, dice) => [1, 6].every(res => prev.includes(res) && dice.includes(res))
console.log(checkCondition(...throws1))
console.log(checkCondition(...throws2))
console.log(checkCondition(...throws3))
Here's the conditional simplified:
2*(a + b + c + d) == a*b + c*d + 16
I wasn't 100% sure about a couple of these answers so I thought I'd test them:
const orig = ([a, b], [c, d]) =>
((a + c === 2 || b + d === 2 || b + c === 2 || a + d === 2) && (a + c === 12 || b + d === 12 || b + c === 12 || a + d === 12));
const A = ([a, b], [c, d]) => 2*(a + b + c + d) == a*b + c*d + 16;
const B = (prev, dice) => [1, 6].every(res => prev.includes(res) && dice.includes(res));
const one_and_six_found = (roll) => roll.includes(1) && roll.includes(6);
const C = (roll1, roll2) => one_and_six_found(roll1) && one_and_six_found(roll2);
const D = (prev, dice) => (prev.includes(1) && dice.includes(1)) || (prev.includes(6) && dice.includes(6));
const E = (prev, dice) => {
const combinations = dice.reduce((acc, curr) => acc.concat(prev.map(curr2 => curr + curr2)), []);
return (combinations.indexOf(2) !== -1 && combinations.indexOf(12) !== -1);
};
const test = (fn) => {
for(let i = 1; i <= 6; i++)
for(let j = 1; j <= 6; j++)
for(let k = 1; k <= 6; k++)
for(let l = 1; l <= 6; l++)
if(fn([i, j], [k, l]) !== orig([i, j], [k, l])) {
console.log('failed on ' + [i, j, k, l].join(', '));
return false;
}
return true;
};
console.log('A', test(A) ? 'success' : 'failed');
console.log('B', test(B) ? 'success' : 'failed');
console.log('C', test(C) ? 'success' : 'failed');
console.log('D', test(D) ? 'success' : 'failed');
console.log('E', test(E) ? 'success' : 'failed');

Declarations and operators issue

Hey guys how can I reorder the declaration of operators such that the result is 0 when logged??
numbers = [23, 12, 71, 10]
operators = [
(a, b) => a + b,
(a, b) => a / b,
(a, b) => a * b,
(a, b) => a - b
];
var result = 1;
operators.forEach(function(op) {
result = Math.floor(op(result, numbers[operators.indexOf(op)]))
});
console.log(result);
I'm halfway there but something just isn't clicking??
Cheers
Looks like this works!
numbers = [23, 12, 71, 10]
operators = [
(a, b) => a + b,
(a, b) => a - b,
(a, b) => a / b,
(a, b) => a * b
];
result = 1;
operators.forEach(function(op) {
result = Math.floor(op(result, numbers[operators.indexOf(op)]))
});
console.log(result);
I brute-forced this ordering to find it -- while result doesn't equal 0, shuffle operators, set result back to 1, and run the forEach, over and over, until result = 0. Here's the code to do it:
// From https://www.w3docs.com/snippets/javascript/how-to-randomize-shuffle-a-javascript-array.html
function shuffleArray(array) {
let curId = array.length;
// There remain elements to shuffle
while (0 !== curId) {
// Pick a remaining element
let randId = Math.floor(Math.random() * curId);
curId -= 1;
// Swap it with the current element.
let tmp = array[curId];
array[curId] = array[randId];
array[randId] = tmp;
}
return array;
}
numbers = [23, 12, 71, 10]
operators = [
(a, b) => a + b,
(a, b) => a - b,
(a, b) => a / b,
(a, b) => a * b
];
let result = 1;
while (result != 0) {
result = 1;
operators = shuffleArray(operators);
operators.forEach(function(op) {
result = Math.floor(op(result, numbers[operators.indexOf(op)]))
});
console.log(result);
}
console.log(operators);
Try to add this code line.
method = ['+','/','*','-']
result = method[operators.indexOf(op)]
Full correct code.
numbers = [23, 12, 71, 10]
method = ['+','/','*','-']
operators = [
(a, b) => a + b,
(a, b) => a / b,
(a, b) => a * b,
(a, b) => a - b
];
var ch = '';
var res = 1
operators.forEach(function(op) {
res = Math.floor(op(res, numbers[operators.indexOf(op)]))
if( res == 0) {
ch = method[operators.indexOf(op)]
}
});
console.log(res);
console.log(ch);

nodejs vs javascript (Two different answers)

var largestNumber = function (nums) {
let comp = (a, b) => {
a = a.split("").reverse().join("");
b = b.split("").reverse().join("");
return a.localeCompare(b) > 0 ? 1 : 0;
};
return nums.map(v => '' + v).sort(comp).reverse().join('');
};
console.log(largestNumber([3, 30, 34, 5, 9]));
In nodejs
output: 9534330
In javascript
output: 9534303
What is happening?
As said in the comments your compare function is non deterministic and the 2 engines result in different outcomes. You could try the following in both versions to see consistent results 9534330.
var largestNumber = function (nums) {
let comp = (a, b) => {
a = a.split("").reverse().join("");
b = b.split("").reverse().join("");
return a.localeCompare(b);
};
return nums.map(v => '' + v).sort(comp).reverse().join('');
};
console.log(largestNumber([3, 30, 34, 5, 9]));

One-Dimensional Array Iteration Using Recursion

I'm trying to iterate over a simple array using recursion. For this specific case, I'm trying to recreate .map() using recursion (without using .map()!. I currently am only pushing the last element in the original array, but I want to push all into the array.
function recursiveMap (arr, func) {
let newArr = [];
if (arr.length === 1){
newArr.push(func(arr));
}
else {
newArr.push(...recursiveMap(arr.slice(1),func));
}
return newArr;
}
You need to to use func on the current item, and spread the result of calling the function on the rest of the array:
function recursiveMap(arr, func) {
return arr.length ? [func(arr[0]), ...recursiveMap(arr.slice(1), func)] : [];
}
const arr = [1, 2, 3];
const result = recursiveMap(arr, n => n * 2);
console.log(result);
Your base case seems wrong. You will need to check for an empty array:
function recursiveMap (arr, func) {
let newArr = [];
if (arr.length === 0) {
// do nothing
} else {
newArr.push(func(arr[0]));
newArr.push(...recursiveMap(arr.slice(1),func));
}
return newArr;
}
Instead you will need to call func (on the first item) when there is at least one element.
With recursion, I find it is helpful to have the base case be the very first thing you check in your function, and short the execution there. The base case for map is if the array has 0 items, in which case you would return an empty array.
if you haven't seen it before let [a, ...b] is array destructuring and a becomes the first value with b holding the remaining array. You could do the same with slice.
function recursiveMap(arr, func){
if(arr.length == 0) return [];
let [first, ...rest] = arr;
return [func(first)].concat(recursiveMap(rest, func));
}
let test = [1,2,3,4,5,6,7];
console.log(recursiveMap(test, (item) => item * 2));
EDIT
Going back to your sample I see you clearly have seen destructuring before xD, sorry. Leaving it in the answer for future readers of the answer though.
Below are a few alternatives. Each recursiveMap
does not mutate input
produces a new array as output
produces a valid result when an empty input is given, []
uses a single pure, functional expression
Destructuring assignment
const identity = x =>
x
const recursiveMap = (f = identity, [ x, ...xs ]) =>
x === undefined
? []
: [ f (x), ...recursiveMap (f, xs) ]
const square = (x = 0) =>
x * x
console.log (recursiveMap (square, [ 1, 2, 3, 4, 5 ]))
// [ 1, 4, 9, 16, 25 ]
Array slice
const identity = x =>
x
const recursiveMap = (f = identity, xs = []) =>
xs.length === 0
? []
: [ f (xs[0]), ...recursiveMap (f, xs.slice (1)) ]
const square = (x = 0) =>
x * x
console.log (recursiveMap (square, [ 1, 2, 3, 4, 5 ]))
// [ 1, 4, 9, 16, 25 ]
Additional parameter with default assignment – creates fewer intermediate values
const identity = x =>
x
const recursiveMap = (f = identity, xs = [], i = 0) =>
i >= xs.length
? []
: [ f (xs[i]) ] .concat (recursiveMap (f, xs, i + 1))
const square = (x = 0) =>
x * x
console.log (recursiveMap (square, [ 1, 2, 3, 4, 5 ]))
// [ 1, 4, 9, 16, 25 ]
Tail recursive (and cute)
const identity = x =>
x
const prepend = x => xs =>
[ x ] .concat (xs)
const compose = (f, g) =>
x => f (g (x))
const recursiveMap = (f = identity, [ x, ...xs ], then = identity) =>
x === undefined
? then ([])
: recursiveMap
( f
, xs
, compose (then, prepend (f (x)))
)
const square = (x = 0) =>
x * x
console.log (recursiveMap (square, [ 1, 2, 3, 4, 5 ]))
// [ 1, 4, 9, 16, 25 ]
// => undefined
recursiveMap (square, [ 1, 2, 3, 4, 5 ], console.log)
// [ 1, 4, 9, 16, 25 ]
// => undefined
recursiveMap (square, [ 1, 2, 3, 4, 5 ])
// => [ 1, 4, 9, 16, 25 ]
Derived from tail-recursive foldl – Note foldl chooses a similar technique used above: additional parameter with default assignment.
const identity = x =>
x
const foldl = (f = identity, acc = null, xs = [], i = 0) =>
i >= xs.length
? acc
: foldl
( f
, f (acc, xs[i])
, xs
, i + 1
)
const recursiveMap = (f = identity, xs = []) =>
foldl
( (acc, x) => acc .concat ([ f (x) ])
, []
, xs
)
const square = (x = 0) =>
x * x
console.log (recursiveMap (square, [ 1, 2, 3, 4, 5 ]))
// [ 1, 4, 9, 16, 25 ]
You could take another approach by using a third parameter for the collected values.
function recursiveMap(array, fn, result = []) {
if (!array.length) {
return result;
}
result.push(fn(array[0]));
return recursiveMap(array.slice(1), fn, result);
}
console.log(recursiveMap([1, 2, 3, 4, 5], x => x << 1));
console.log(recursiveMap([], x => x << 1));
welcome to Stack Overflow. You could either pass result to itself like in the following example:
function recursiveMap (arr, func,result=[]) {
if (arr.length === 0){
return result;
}
return recursiveMap(
arr.slice(1),
func,
result.concat([func(arr[0])])
);
}
console.log(recursiveMap([1,2,3,4],x=>(x===3)?['hello','world']:x+2));
Or define a recursive function in your function:
function recursiveMap (arr, func) {
const recur = (arr, func,result=[])=>
(arr.length === 0)
? result
: recur(
arr.slice(1),
func,
result.concat([func(arr[0])])
);
return recur(arr,func,[])
}
console.log(recursiveMap([1,2,3,4],x=>(x===3)?['hello','world']:x+2));
Add newArr.push(func(arr[0])); before calling again the function
function recursiveMap (arr, func) {
let newArr = [];
if (arr.length === 1){
newArr.push(func(arr));
}
else {
newArr.push(func(arr[0]));
newArr.push(...recursiveMap(arr.slice(1),func));
}
return newArr;
}
console.log(recursiveMap([1,2,3], function(a){return +a+2}))
Same but modified answer with bugs corrected
function recursiveMap (arr, func) {
let newArr = [];
if(arr.length){
newArr.push(func(arr[0]));
if(arr.length > 1){
newArr.push(...recursiveMap(arr.slice(1),func));
}
}
return newArr;
}
console.log(recursiveMap([1,2,3], function(a){return a+2}))

Implement Foldl function in Javascript

I'm trying to write a function that implements foldl in JavaScript. I'm trying to use recursion in the function but not being able to implement it.
var foldl = function(f, acc, array) {
if (array.length == 0) {
return acc;
} else {
return f(array[0], foldl(f, acc, array.slice(-1)));
}
}
console.log(foldl(function(x, y) {
return x + y
}, 0, [1, 2, 3]));
console.log(foldl(function(x,y){return x+y}, 0, [1,2,3]));
Error Message..
RangeError: Maximum call stack size exceeded
Your challenge, as mentioned above, is that you're returning an array of the last element. And you're always returning an array of the last element.
What is missing from the answers above is that they're only good for folding to the right.
For the right case, you can just use .slice(1), and that will pull everything after the head.
For the fold left case, you need to specify how far you need to go .slice(0, arr.length - 1).
const foldr = (f, acc, arr) => {
if (!arr.length) {
return acc;
} else {
const head = arr[0];
const tail = arr.slice(1);
return foldr(f, f(acc, head), tail);
}
};
foldr((x, y) => x + y, 0, [1, 2, 3])// 6
const foldl = (f, acc, arr) => {
if (!arr.length) {
return acc;
} else {
const head = arr[arr.length - 1];
const tail = arr.slice(0, arr.length - 1);
return foldl(f, f(acc, head), tail);
}
};
foldl((x, y) => x + y, 0, [3, 2, 1]); // 6
This:
array.slice(-1)
should be:
array.slice(1)
slice(-1) returns the array containing the last element. As you're using the first element of the array, you want the array without that element instead. slice(1) will return the array without the first element.
slice(-1) return only the last element. If you want to recurse over the array, use slice(1) instead, which will return all elements except the first:
var foldl = function(f, acc, array) {
if (array.length == 0) {
return acc;
} else {
return f(array[0], foldl(f, acc, array.slice(1)));
}
}
console.log(foldl(function(x, y) {
return x + y
}, 0, [1, 2, 3]));
Note that foldl and foldr can both be implemented in a way that iterates thru the input list in first-to-rest (left-to-right) order. Awkward negative indexes or calculating precise slice positions are not needed.
const Empty =
Symbol ()
const foldl = (f, acc, [ x = Empty, ...xs ]) =>
x === Empty
? acc
: foldl (f, f (acc, x), xs)
const foldr = (f, acc, [ x = Empty, ...xs ]) =>
x === Empty
? acc
: f (foldr (f, acc, xs), x)
const pair = (a,b) =>
`(${a} ${b})`
const data =
[ 1, 2, 3 ]
console.log (foldl (pair, 0, data))
// (((0 1) 2) 3)
console.log (foldr (pair, 0, data))
// (((0 3) 2) 1)
You can use xs[0] and xs.slice(1) if you don't want to use the destructuring assignment
const foldl = (f, acc, xs) =>
xs.length === 0
? acc
: foldl (f, f (acc, xs[0]), xs.slice (1))
const foldr = (f, acc, xs) =>
xs.length === 0
? acc
: f (foldr (f, acc, xs.slice (1)), xs [0])
const pair = (a,b) =>
`(${a} ${b})`
const data =
[ 1, 2, 3 ]
console.log (foldl (pair, 0, data))
// (((0 1) 2) 3)
console.log (foldr (pair, 0, data))
// (((0 3) 2) 1)
...xs via destructuring assignment used in the first solution and slice used in the second solution create intermediate values and could be a performance hit if xs is of considerable size. Below, a third solution that avoids this
const foldl = (f, acc, xs, i = 0) =>
i >= xs.length
? acc
: foldl (f, f (acc, xs[i]), xs, i + 1)
const foldr = (f, acc, xs, i = 0) =>
i >= xs.length
? acc
: f (foldr (f, acc, xs, i + 1), xs [i])
const pair = (a,b) =>
`(${a} ${b})`
const data =
[ 1, 2, 3 ]
console.log (foldl (pair, 0, data))
// (((0 1) 2) 3)
console.log (foldr (pair, 0, data))
// (((0 3) 2) 1)
Above our foldl and foldr are almost perfect drop-in replacements for natives Array.prototype.reduce and Array.prototype.reduceRight respectively. By passing i and xs to the callback, we get even closer
const foldl = (f, acc, xs, i = 0) =>
i >= xs.length
? acc
: foldl (f, f (acc, xs[i], i, xs), xs, i + 1)
const foldr = (f, acc, xs, i = 0) =>
i >= xs.length
? acc
: f (foldr (f, acc, xs, i + 1), xs[i], i, xs)
const pair = (acc, value, i, self) =>
{
console.log (acc, value, i, self)
return acc + value
}
console.log (foldl (pair, 'a', [ 'b', 'c', 'd' ]))
// a b 0 [ b, c, d ]
// ab c 1 [ b, c, d ]
// abc d 2 [ b, c, d ]
// => abcd
console.log (foldr (pair, 'z', [ 'w', 'x', 'y' ]))
// z y 2 [ x, y, z ]
// zy x 1 [ x, y, z ]
// zyx w 0 [ x, y, z ]
// => zyxw
And finally, reduce and reduceRight accept a context argument. This is important if the folding function f refers to this. If you want to support a configurable context in your own folds, it's easy
const foldl = (f, acc, xs, context = null, i = 0) =>
i >= xs.length
? acc
: foldl ( f
, f.call (context, acc, xs[i], i, xs)
, xs
, context
, i + 1
)
const foldr = (f, acc, xs, context = null, i = 0) =>
i >= xs.length
? acc
: f.call ( context
, foldr (f, acc, xs, context, i + 1)
, xs[i]
, i
, xs
)
const obj =
{ a: 1, b: 2, c: 3, d: 4, e: 5 }
// some function that uses `this`
const picker = function (acc, key) {
return [ ...acc, { [key]: this[key] } ]
}
console.log (foldl (picker, [], [ 'b', 'd', 'e' ], obj))
// [ { b: 2 }, { d: 4 }, { e: 5 } ]
console.log (foldr (picker, [], [ 'b', 'd', 'e' ], obj))
// [ { e: 5 }, { d: 4 }, { b: 2 } ]

Categories