I am creating a function memo return a function that, when called, will check if it has already computed the result for the given argument and return that value instead if possible.
Right now my key only contains the first argument passed in as my key to check if the function was already run.
const memo = function(func) {
const memoizedFunc = function () {
let result;
if (memoizedFunc.cache[arguments[0]] !== undefined) {
result = memoizedFunc.cache[arguments[0]];
} else {
result = func.apply(null, arguments);
memoizedFunc.cache[arguments[0]] = result;
}
return result;
}
memoizedFunc.cache = {};
return memoizedFunc;
};
So if we run this using the test function:
function memoAdd(num1, num2){
return num1 + num2;
}
memo(memoAdd(1, 2)));
memo(memoAdd(1, 3))); // -> since it's the first argument that we use as
// the key, it will still pull up 3 as the answer even if the answer should
// be four
Any idea how should I fix this so I'll give different results for different arguments?
Your test call will fail because it is not passing a callable to memo, but the results of the function.
If the idea is to avoid repeated computation and merely return the same result, you could do it like this:
var function_cache = {};
const memo1 = function(f, args) {
var sig = JSON.stringify(args);
if (f.cache == undefined) {
f.cache = {};
}
if (f.cache[sig] !== undefined) {
console.log('Value from Cache');
return f.cache[sig];
}
console.log('Value from Computation');
f.cache[sig] = f.apply(null, args);
return f.cache[sig];
}
function memoAdd(num1, num2){
return num1 + num2;
}
console.log(memo1(memoAdd, [1, 2]));
console.log(memo1(memoAdd, [1, 3]));
console.log(memo1(memoAdd, [1, 2]));
console.log(memo1(memoAdd, [1, 3]));
In this case, the hash cache is added to the function that is passed, and the arguments are converted to a string signature via JSON.stringify - which is used to look up the prior value and return it.
If your goal is to have a callable that does this so you don't need to wrap it in memo each time, you could tweak this:
const memo2 = function(f) {
if (f.cache == undefined) {
f.cache = {};
}
const newFunc = function() {
var sig = JSON.stringify(arguments);
if (f.cache[sig] !== undefined) {
console.log('Value from Cache');
return f.cache[sig];
}
console.log('Value from Computation');
f.cache[sig] = f.apply(null, arguments);
return f.cache[sig];
}
return newFunc;
}
function memoAdd(num1, num2){
return num1 + num2;
}
var myFunc = memo2(memoAdd);
console.log(myFunc(1,2));
console.log(myFunc(1,3));
console.log(myFunc(1,2));
console.log(myFunc(1,3));
In this case the passed in function is locked-in by the closure, and we still cache results in f.cache.
Related
I have tried writing the below code to find sum of 'n' numbers using sum function. I am getting the correct response in output. But i am unable to return that using sum function, as i always have to return a function, which is required for curried effect.
Please help. Thanks in advance.
var output = 0,
chain;
function sum() {
var args = Array.prototype.slice.call(arguments);
output += args.reduce(function(a, b) {
return a + b;
});
sumCurried = sum.bind(output);
sumCurried.val = function() {
return output;
}
return sumCurried;
}
debugger;
document.getElementById('demo').innerHTML = sum(1, 2)(3)(4);
// document.getElementById('demo').innerHTML = sum(1)(3)(4);
<p id='demo'></p>
enter code here
You can add a stop condition to the curried function, for example - if the function is called without an argument return the output:
var output = 0,
chain;
function sum() {
var args = Array.prototype.slice.call(arguments);
if(args.length === 0) {
return output;
}
output += args.reduce(function(a, b) {
return a + b;
});
sumCurried = sum.bind(output);
return sumCurried;
}
console.log(sum(1, 2)(3)(4)());
<p id='demo'></p>
The returned curry function has a val property, which is a function that returns the current value:
var output = 0,
chain;
function sum() {
var args = Array.prototype.slice.call(arguments);
output += args.reduce(function(a, b) {
return a + b;
});
sumCurried = sum.bind(output);
sumCurried.val = function() {
return output;
}
return sumCurried;
}
console.log(sum(1, 2)(3)(4).val());
<p id='demo'></p>
Why would you use currying at all? However, here is a shorter version:
const sum = (...args) => {
const func = (...s)=> sum(...args,...s);
func.value = args.reduce((a,b)=>a+b,0);
return func;
};
//usable as
sum(1,2).value,
sum(1,1)(1).value,
sum(1,1)(1,1)(1,1).value
And you always need to end the currying chain. However, it can be shortified:
func.valueOf = ()=> args.reduce((a,b)=>a+b,0);
//( instead of func.value = ... )
So when called you can do:
+sum(1,2,3)
+sum(1)(1)(1)
I am trying to write a function that takes functions as arguments (as many as it gets) and returns them. The function funcArg should return 'Called me'. I used Array.prototype.slice.call(arguments); to create an array but I don't know how to call die functions in that array. Any ideas? Thanks!!
var caller = function() {
return "Called ";
};
var adder = function() {
return " me";
};
var funcArgs = function() {
var myArray = Array.prototype.slice.call(arguments);
}
funcArgs(caller);
funcArgs(calleradder);
You can do this using reduce.
var funcArgs = function() {
var functions = Array.prototype.slice.call(arguments);
return functions.reduce(function(total, f) {
return total + f();
}, '');
};
The way this works if you start off with an array of functions. We then go through each function one at a time. We then call that function and append it to the result of the previous function. Breaking this down into simpler code would look like this:
var funcArgs = function() {
var functions = [caller, adder];
var result = '';
result += functions[0](); // caller();
result += functions[1](); // adder();
return result;
};
If you have an array of functions you can loop over them with forEach.
var caller = function() {
return "Called "
}
var adder = function() {
return " me"
}
var funcArgs = function() {
var myArray = Array.prototype.slice.call(arguments);
myArray.forEach(function (fn) {
console.log(fn())
})
}
funcArgs(caller, adder); // "Called me"
If you want to actually return the values, rather than just console.log them, you can use reduce to return the strings concatenated (or whatever else)
var funcArgs = function() {
var myArray = Array.prototype.slice.call(arguments);
return myArray.reduce(function (acc, fn) {
return acc + fn()
}, '')
}
Straightforward question:
Can I negate a callback function that returns true or false o an array.filter() statement? e.g.
//the callback function
function isEven(element, index, array){
if (index%2 == 0 || index == 0){
return true;
}
return false;
}
//what i want to do with that function
//arr[i] is a string
var evens = arr[i].split("").filter(isEven); //works
var odds = arr[i].split("").filter(!isEven); // doesn't work
the above line gives me the error TypeError: false is not a function
Question with some background:
I'm taking on some Hackerrank challenges and i've come across an exercise that requires to take a string and process it, so the output is: The characters with even index values make a new string and the characters in odd index positions make another string , 0 counts as even.
Input
airplane
Output
evens = 'arln'
odds = 'ipae'
I have already solved it by looping through the string, evaluating the index and then pushing the value to the correspondent new array (which i later convert to a string), but it has occurred to me i could be done in a more functional way, using the Array.prototype.filter() function.
now I create a new function that evaluates whether the index number is even or not, and I'd like to use that same function to fill both arrays (evens and odds), like this (now you can refer to the straightforward question part):
var evens = arr[i].split("").filter(isEven); //works
var odds = arr[i].split("").filter(!isEven); // doesn't work
The simplest way to do this would be to just pass an anonymous function which returns the negated result of isEven.
var evens = arr[i].split("").filter(function(el, index, array) {
return !isEven(el, index, array);
});
But you could take this a step further and write a not function which essentially generates the anonymous function for you. Here's an example of such a function.
var input = [0, 1, 2, 3, 4, 5];
function isEven(value) {
return value % 2 === 0;
}
function not(f) {
return function() {
return !f.apply(null, arguments);
}
}
var output = input.filter(not(isEven));
console.log(output);
If you're in an environment that supports rest parameters then you could write your not function like this.
var input = [0, 1, 2, 3, 4, 5];
function isEven(value) {
return value % 2 === 0;
}
function not(f) {
return function(...args) {
return !f.apply(null, args);
}
}
var output = input.filter(not(isEven));
console.log(output);
You would need to pass in an anonymous function and then negate isEven in there:
var odds = arr[i].split("").filter(function(a, index, array) {
return !isEven(a, index, array);
});
Simple Example:
Working Example
function isEven(n) {
return n % 2 === 0;
}
var arr = [0,1,2,3,4,5,6,7,8,9];
var a = arr.filter(isEven);
var b = arr.filter(function(a) {
return !isEven(a);
});
The solution I use is something like this:
var numbers = [0,1,2,3,4,5];
var evens = [];
var odds = [];
function isEvenOrNot(getEven) {
return function(num) {
if (num % 2 == 0 || num == 0){
return true;
}
return false;
}
}
evens = numbers.filter(isEvenOrNot(true));
odds = numbers.filter(isEvenOrNot(false));
console.log(evens); // [0,2,4]
console.log(odds); // [1,3,5]
I know I can get the String representation of a function without calling it like this
function storeData(id, data) { console.log("Doing stuff..") };
storeData.toString(); //"function storeData(id, data) { console.log("Doing stuff..") }"
And I could in theory parse the resulting String to pull out the variable names. Any takers on writing that code? Is there an easier way? (I don't need to worry about minification)
try to use the following code:
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var ARGUMENT_NAMES = /([^\s,]+)/g;
function getParamNames(func) {
var fnStr = func.toString().replace(STRIP_COMMENTS, '');
var result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
if (result === null)
result = [];
return result;
}
getParamNames(getParamNames) // returns ['func']
getParamNames(function (a, b, c, d) { }) // returns ['a','b','c','d']
getParamNames(function (a,/*b,c,*/d) { }) // returns ['a','d']
getParamNames(function () { }) // returns []
I am working on the curring function and partial application,
I am trying to improve the function schonfinkelize:
function schonfinkelize(fn){
var
slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function(){
var
new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
}
}
This function permit to pass as argument a function and a part of the argument of the function passed as argument (partial application) so the first time you return a function and then when you fire the function again the result.
function add(x, y, z){
return x + y + z;
}
var val = schonfinkelize(add, 1, 2);
console.log( val(3) ) // console output--> 6
I want check inside schonfinkelize the number of arguments need to the function "add" (but it should work with every function) so I can choose when return another function or directly the result of the function "add".
bacause if I use schonfinkelize in this way:
var val2 = schonfinkelize(add, 1, 2, 3);
console.log( val2 ) // --> function
console.log( val2() ) // --> 6
I have to fire the function two time, instead a want avoid this behavior and define directly the value if the arguments are sufficient.
A possible solution could be the following:
function schonfinkelize(fn){
var
slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
//* I have added this ********
if(fn.apply(null, stored_args))
return fn.apply(null, stored_args);
//****************************
return function(){
var
new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
}
}
Could be because it returns immediately the result if the fn.apply(null, stored_args) return something that is not "null" or "NaN" but I think is not really performant and then I want work with the arguments.
As long as you put in place a requirement that the parameters defined for the function passed reflect the actually number of arguments that are to be ultimately received, you can use the .length property of the function to do the comparison of passed arguments to anticipated arguments.
function schonfinkelize(fn) {
if (fn.length === arguments.length - 1)
return fn.apply(this, [].slice.call(arguments, 1));
var
slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function(){
var
new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
}
}
Side note... you can avoid the .slice() if you cache the fn in a new variable, and overwrite the first argument with the this value, then use .call.apply()...
if (fn.length === arguments.length - 1) {
var func = fn;
arguments[0] = this;
return func.call.apply(func, arguments);
}
In strict mode browsers you could even avoid having the make the new variable since the parameters are no longer mapped to changes in the arguments. But this doesn't work in browsers that don't support strict mode.
I don't think there is a correct way to determine number of arguments for arbitrary function. I prefer to store len in function if it is necessary, and check if it is defined, and if it is and if fn.len == stored_args.length then return function that just returns value.
function schonfinkelize(fn){
var
slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
if (fn.len != undefined && fn.len == stored_args.length) {
var val = fn.apply(null, stored_args);
return function () {
return val;
};
}
return function () {
var
new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
};
}
var f = function (a, b, c) {
return a + b + c;
};
f.len = 3;
var g = schonfinkelize(f, 1, 2);
alert(g); // function () { var new_args = slice.call(arguments), args = stored_args.concat(new_args); return fn.apply(null, args); };
alert(g(3)); // 6
var g = schonfinkelize(f, 1, 2, 3);
alert(g); // function () { return val; };
alert(g()); // 6
I want propose also a personal evolution of the code but I have to said thanks to squint to has resolved the problem, simply suggest me to use the property .length.
The next level it is in my opinion permit to create a partial function able to be called every time you want until you finish to fill all the arguments, I have also simplified the code:
function schonfinkelize(fn, stored_args){
if(fn.length == stored_args.length)
return fn.apply(null, stored_args);
return function(){
var
new_args = arguments[0],
args = stored_args.concat(new_args);
if(fn.length == args.length)
return fn.apply(null, args);
return schonfinkelize(fn, args);
}
}
function add(x, y, w, z){
return x + y + w + z;
}
var
val = schonfinkelize(add, [1, 2, 3, 4]),
val2 = schonfinkelize(add, [1, 2]),
val3 = schonfinkelize(add, [1]);
// checking
console.log(val); // output --> 10 // called only 1 time
console.log(val2([3, 4])); // output --> 10 // called in 2 times
val3 = val3([2]);
val3 = val3([3]);
console.log(val3([4])); // output --> 10 // called 4 times!