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))
Related
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));
In a recent interview, I was asked to write a function that adds numbers and accepts parameters like this:
add(1)(2)(3) // result is 6
add(1,2)(3,4)(5) // result is 15
The number of parameters is not fixed, and the arguments can be either passed in sets or individually.
How can I implement this add function?
Given your examples, the number of parameters is fixed in some ways.
As #ASDFGerte pointed out, your examples seem to return the result after three invocations. In this case a simple implementation without introducing terms like variadic and currying could be
function add(...args1){
return function(...args2){
return function(...args3){
return args1.concat(args2).concat(args3).reduce((a,b)=>a+b)}}}
console.log(add(1)(2)(3))
console.log(add(1,2)(3,4)(5))
Every invocation accepts a variable number of parameters.
However it would be nice to generalize the construction of this nested functions structure and you can accomplish that with currying.
But if you want to allow an arbitrary number of invocations, when you should stop returning a new function and return the result? There is no way to know, and this is a simple, unaccurate and partial explanation to give you the idea of why they said you cannot accomplish what they asked you.
So the ultimate question is: is it possible that you misunderstood the question? Or maybe it was just a trick to test you
Edit
Another option would be to actually invoke the function when no arguments are passed in, change the call to add(1)(2)(3)()
Here an example recursive implementation
function sum (...args) {
let s = args.reduce((a,b)=>a+b)
return function (...x) {
return x.length == 0 ? s : sum(s, ...x)
};
}
console.log(sum(1,2)(2,3,4)(2)())
At every invocation computes the sum of current parameters and then return a new function that:
if is invoked without parameters just return the current sum
if other numbers are passed in, invokes recursively sum passing the actual sum and the new numbers
I'm a bit late to the party, but something like this would work (a bit hacky though in my opinion):
const add = (a, ...restA) => {
const fn = (b, ...restB) => {
return add([a, ...restA].reduce((x, y) => x + y) + [b, ...restB].reduce((x, y) => x + y))
};
fn.valueOf = () => {
return [a, ...restA].reduce((x, y) => x + y)
};
return fn;
}
This function returns a function with a value of the sum. The tests below are outputing the coerced values instead of the actual functions.
console.log(+add(1,2)(3,4)(5)); // 15
console.log(+add(1)) // 1
console.log(+add(1)(2)) // 3
console.log(+add(1)(2)(3)) // 6
console.log(+add(1)(2)(3)(4)) // 10
Since it's a currying function, it will always return another function so you can do something like this:
const addTwo = add(2);
console.log(+addTwo(5)); // 7
using reduce and spread it can be done as below
function calc(...args1){
return function (...args2){
return function (...args3){
let merge = [...args1, ...args2, ...args3]
return merge.reduce((x ,y)=> x + y) ;
}
}
}
let sum = calc(10)(1)(4);
console.log("sum",sum);
They probably wanted to know how comfortable you were with "javascript internals", such as how and when methods like Function#toString and Function#valueOf, Function#[Symbol.toPrimitive] are called under the hood.
const add = (...numbers) => {
const cadd = (...args) => add(...args, ...numbers);
cadd[Symbol.toPrimitive] = () => numbers.reduce((a, b) => a + b);
return cadd;
}
console.log(
`add(1,2)(3,4)(5) =>`, add(1,2)(3,4)(5),
); // result is 15
console.log(
`add(1,2) =>`, add(1,2),
); // result is 3
console.log(
`add(1,2)(5)(1,2)(5)(1,2)(5)(1,2)(5) =>`, add(1,2)(5)(1,2)(5)(1,2)(5)(1,2)(5),
); // result is 32
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);
Given I have a function called sum module imported from a 3rd party module Calculator. Here's how I use it:
Calculator.sum(1, 2) // returns 3
I don't know the implementation of Calculator.sum. What if I want to modify the arguments passed to Calculator.sum before executing sum, so that instead of taking the original numbers (1, 2, 3, etc), sum will take their squared values (1, 4, 9, etc) ? For example:
Calculator.sum(1, 2) // returns 5
Calculator.sum(2, 3) // returns 13
Calculator.sum(3, 4) // returns 25
Note: This is just an example of my actual problem, I don't actually need a Calculator.sum function to calculate sum of squares 😀
Couldn't you just store it under another name and overwrite it ?
Calculator.sum_stored = Calculator.sum;
Calculator.sum = function(a,b){
return Calculator.sum_stored(Math.sqrt(a),Math.sqrt(b));
};
Then you can just call Calculator.sum as you wanted to.
You could simply decorate the original function with you extra functionality, then call the original function with whatever values you wish.
If you are going to do something like this, you should really define a different function eg, calulator.squareAdd.
// this is your library object
const Calculator = {
sum: (...args) => args.reduce((x, y) => x + y, 0)
}
console.log(
'before decoration',
Calculator.sum(1, 2)
)
// save a reference to the original function
const origSum = Calculator.sum
// decorate the sum function with your own function
Calculator.sum = function(...args) {
return origSum.apply(Calculator, args.map(x => Math.pow(x, 2)))
}
// call the decorated function
console.log(
'after decoration',
Calculator.sum(1, 2), // returns 5
Calculator.sum(2, 3), // returns 13
Calculator.sum(3, 4) // returns 25
)
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js"></script>
You can modify the arguments in side the method like this ->
Calculator.sum(a,b) {
return a*a + b*b;
}
And if you want your method to be flexible then you can pass a third argument that will identify what operation needs to be performed on the arguments.
Calculator.sum(a,b,'square'){
//use switch case here to return the correct result.
}
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