I understand all the code until it hits the zero? why is it needed here?
const sum = (function() {
"use strict";
return function sum(...args) {
return args.reduce((a, b) => a + b, 0);
};
})();
The second argument to reduce() specifies the initial value. It can literally be anything.
In your example, it is initializing it to 0. The parameters a and b are poorly named. Normally the parameters are something more like result and value, which you could then see you are adding value to result (which was initialized to 0).
const sum = [1,2,3].reduce((result, value) => {
console.log({ result, value });
return result + value;
}, 0);
console.log('Sum', sum);
Related
How to implement a function sum which will take parameters like the below and should give the output of the total sum without calling it at the end with an empty parameter call.
sum(1,2..n)(5,6…n)…(n)
example:
console.log("output should be: ", sum(1)(2,3)(4,5,6)) // output should be: 21
Note:
I know we can use valueOf but that will only work if we are parsing the result in primitive value.
I don't want solution for console.log(sum(1)(2,3)(4,5,6)()) // 21 as its solution I know which is:
function add(...args) {
let a = args.reduce((a, b) => a + b, 0)
function sum(...args){
let b = args.reduce((a, b) => a + b, 0)
if(b){
return add(a+b)
}
return a
}
return sum
}
Any help/guidance or reference by which it can be achieved will be helpful.
For the problem, I was tasked to create a function that mimics the reduce method and test
it against the following where I should get the answer of 8.
I don't understand how the callback (acc, el, index, arr) portion brings in the "add" function.
With 2 parameters of (a, b) where does the parameters of the forEach come into play?
// function to mimic reduce
function reduce(array, callback, initial) {
if(Array.isArray(array) {
let acc;
if (initial === undefined) {
acc = array[0];
array = array.slice(1);
} else {
acc = initial;
}
array.forEach(function(el, index, arr) {
acc = callback(acc, el, index, arr);
});
return acc;
}
return "The first arg should be an array";
}
// Code to test against reduce function
var nums = [4, 1, 3]
var add = function(a, b) { return a + b;}
reduce(nums, add, 0) // answer is 8
When you call
reduce(nums, add, 0);
nums becomes the value of array, add becomes the value of callback, and 0 becomes the value of initial.
Then when you call array.forEach(), your function does acc = callback(acc, el, index, arr), which calls add(). Inside add(), a gets the value of acc and b gets the value of el (the other two arguments you pass to callback are being ignored by add -- most reduction functions don't need to use them, but they're passed for completeness). The result is stored back in acc, which will be passed again on the next iteration of forEach().
BTW, the code that initializes acc doesn't look right. You shouldn't be testing whether arr is an array (it has to be), you should check whether initial was supplied.
var acc;
if (initial === undefined) {
acc = arr[0];
arr = arr.slice(1);
} else {
acc = initial;
}
I am trying to write a simple compose function that takes a series of functions, and composes them like so:
compose(func1, func2, func3)(n) === func1(func2(func3(n)))
I do so by recursing through a rest parameter,
var compose = function(...args) {
return (n) => {
if (args.length) {
return args[0](compose(args.slice(1)));
} else {
return n;
}
};
};
I then attempt to compose a new function made up of a series of other functions,
var plusOneAndTwo = compose((n) => n + 1, (n) => n + 2);
plusOneAndTwo(1);
Instead of returning 4, I get back the body of the inner, anonymous function inside of compose as a string,
"(n) => {
if (args.length) {
return args[0](compose(args.slice(1)));
} else {
return n;
}
}1"
Note the "1" at the end of the string! I have no idea why this is happening, and in particular I'm perplexed by how a 1 is getting appended to the end of that.
Any clarification is appreciated, thanks!
The problem occurs in the recursive call to compose.
In particular, you are not passing the parameter n to it (as also suggested by others above). Furthermore, you need to expand the rest parameter in the call.
You should use something like:
return args[0](compose(...args.slice(1))(n))
In your case, you are simply returning:
return args[0](compose(args.slice(1)));
In your example you call compose((n) => n + 1, (n) => n + 2);. Compose then returns a function taking n as a parameter. In this function, args.length becomes 1 (i.e. true-is), args[0] becomes (n) => n + 1 and args.slice(1) becomes [(n) => n + 2].
Next, you call this returned function with the parameter n = 1. As args.length is 1, the if() statement will go into the if() case. In this if case, it will call args[0] with the argument compose(args.slice(1)).
In this recursive call, compose(args.slice(1)) is evaluated to a function, taking n as a parameter and the same function body.
This function is then given as the parameter n to args[0] (in the outer call). Recall that args[0] in this scenario is the function (n) => n + 1.
Thus the call as a whole is equivalent to:
// returned from the recursive call to compose(args.slice(1))
var n = (n) => {
if (args.length) {
return args[0](compose(args.slice(1)));
} else {
return n;
}
}
// applied to arg[0] == (n) => n + 1
return n + 1
This means that the code will attempt to add a function with the number 1.
In JavaScript adding a function and a number results in both objects coerced into a string. Casting a number into a string is trivial, casting a function into a string returns the function source code. These strings are then added to give the return value you saw: The function body as a string with the 1 at the end.
You just have to call the composed function:
return args[0](compose(...args.slice(1))(n));
Or without recursion it'll be:
const compose = (...fns) => start => fns.reduceRight((acc, fn) => fn(acc), start);
You could take a different approach by returning a new function or returning the last function for calling with arguments.
const
compose = (...fns) => fns.length
? v => compose(...fns.slice(0, -1))(fns.pop()(v))
: v => v,
fn1 = n => n * 5,
fn2 = n => n + 2,
fn3 = n => n * 7;
console.log(fn1(fn2(fn3(1))));
console.log(compose(fn1, fn2, fn3)(1));
The simplest question for that is like to write a function that could return the sum of all the parameters. How I can do that?
function add () {
}
add(1)(2)(3)(); //6
add(5)(6)(7)(8)(9)() //35
I think this is exactly what you need:
function add(value) {
return (val) => val !== undefined ? add(value + val) : value;
}
console.log(add(2)(2)()); //4
console.log(add(2)(2)(5)(5)()); //14
console.log(add(1)(1)(1)(1)(1)()); //5
console.log(add(1)(1)(0)(1)(1)()); //4
How it works
For every call it declares a function inside, in result it creates a closure(persistent scope) in every call. Function created in that way has access to its parameter + previous call parameter due to existing closure.
So if I call add(2)(3)():
add(2) - returns function with visible 2 value
add(2)(3) - calls second function with input 2 + 3 and return third function with visible value equal 5
add(2)(3)() - ends computation due to empty param and returns the value
To finish the computation pipe the last call needs to be without a value.
The basic idea is to create a closure with a variable sum that we can update, and return the sum if the value is undefined, or the the inner function:
const add = (n) => {
let sum;
const inner = (n) => n === undefined ? sum : (sum = (sum || 0) + n, inner);
return inner(n);
};
console.log(add(1)(2)(3)()); //6
console.log(add(5)(6)(7)(8)(9)()); //35
I would just use a Spread syntax like this:
function add(...values) {
return values.reduce((sum, value) => sum + value, 0)
}
console.log(add(1, 4, 34, 45, 3, 4, 5))
Trying to get the average of an array.
Array.prototype.average = function() {
var sum = 0;
this.reduce(function(a, b) {
sum = a + b;
});
return sum / this.length;
};
[2, 15, 7].average();
Why does the average function call return NaN?
Your program didn't work because, a has the accumulated value from the previous function call. The first time, first two values of the array will be used. So sum will become 17 (2 + 15). Since you are not returning anything from the function, undefined will be returned, by default, and that will be used as the value for a, in the next call. So, the evaluation goes like this
a: 2, b: 15 => 17
a: undefined, b: 7 => NaN
So, sum will have NaN, since undefined + 7 makes it so. Any numeric operation on NaN, will always give NaN, that is why NaN / this.length, gives you NaN. You can fix your program, just by returning the current value of sum whenever the function is called, so that on the next function call, a will have proper accumulated value.
Array.prototype.average = function() {
var sum = 0;
this.reduce(function(a, b) {
sum = a + b;
return sum;
});
return sum / this.length;
};
But we are not making use of the power and flexibility of reduce here. Here are two important points to consider when using reduce.
reduce accepts a second parameter which says the initial value to be used. Whenever possible, specify that.
The first parameter in the function passed to reduce accumulates the result and that will be returned finally, make use of that. No need to use a separate variable to keep track of the results.
So your code would look better like this
Array.prototype.average = function() {
var sum = this.reduce(function(result, currentValue) {
return result + currentValue
}, 0);
return sum / this.length;
};
console.log([2, 15, 7].average());
# 8
reduce actually works like this. It iterates through the array and passes the current value as the second parameter to the function and the current accumulated result as the first parameter and the value returned from the function will be stored in the accumulated value. So, the sum is actually found like this
result: 0 , currentValue: 2 => 2 (Initializer value `0`)
result: 2 , currentValue: 15 => 17
result: 17, currentValue: 7 => 24
Since it ran out of values from the array, 24 will be returned as the result of the reduce, which will be stored in sum.
Your anonymous addition function does not return any value, reduce works with functions that return a value:
Try:
Array.prototype.average = function() {
var sum = this.reduce(function (a, b) {
return a + b;
}, 0);
return sum/this.length;
};
Another possibility is that your array contains strings instead of numbers, thus you could want to coerce them to numbers with return (+a) + (+b); as if you have "10.0" and "20.0", adding them together gives "10.020.0", which divided by any number again gives NaN.
You already have the answer to your question provided by others, but I thought I'd just expand on my comment with an example.
if (!Array.prototype.average) {
Object.defineProperty(Array.prototype, 'average', {
value: function () {
if (typeof this === 'undefined' || this === null) {
throw new TypeError('Cannot convert argument to object');
}
var object = Object(this);
return [].reduce.call(object, function (result, currentValue) {
return +(currentValue) + result;
}, 0) / object.length;
}
});
}
var out = document.getElementById('out');
out.textContent += [2, 15, 7].average() + '\n';
out.textContent += [].average.call({
0: '2',
1: '15',
2: '7',
length: 3
}) + '\n';
out.textContent += [].average.call('123') + '\n';
<pre id="out"></pre>
Whatever value is returned from reduce, it becomes the first parameter in the next call, so you have to return something. Also if you're extending prototypes on purpose, make sure to check for existence first so you're not overriding someone else's method.
There is no need to create any other variables in the function body as it can all be implemented in one line.
if(!Array.prototype.average) {
Array.prototype.average = function() {
return this.reduce(function(a, b){ return a + b; }) / this.length;
};
}
Also note that the second parameter of reduce isn't very useful when summing numbers, unless you're trying to sum up from a number other than zero, which isn't exactly summing a set of numbers.
There is more info on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce