I'm stuck on currying a function with many parameters. What I want to do is take the result of return function and pass it to the next functions.
What I want is similar to this
return this.function(
this.function(
this.function(this.data, this.filterCondition1),
this.filterCondition2),
this.filterCondition3
);
What it basically does is it takes some data, filters it by condition and then feeds it to the next filter that also takes in a second different condition
What I've tried is:
curryFunction(data, filter, filterFunction) =>{
const filteredData = filterFunction(data)
return helper( curryFilter, curryFunction) =>{
return curryFunction(filteredData, curryFilter, curryFunction)
}
}
However, this function returns a function at the end instead of a value.
Basically, it's an infinite loop. How exactly would I go about solving this problem? Thanks
Based on your comment of
take the result of the previous function and pass it to the next, similar to add([1]).add(2).add(3), which will result in 6
I think it is might be better to implement via class function.
class NumberResult {
value = 0;
constructor (value: number) {
this.value = value;
}
function add(a: number) {
this.value = this.value + a;
return this;
}
function add(a: number[]) {
// overload to handle array
}
}
const result = new NumberResult(1);
result.add(1).add(2).add(3);
console.log(result.value);
Related
in need of help with a codecamp challenge:
Arguments Optional - The challenge
https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/arguments-optional
My Question
I know this can be done with the arguments object (see figure 1), where I can call the function again when the second value is undefined so I've gone for a different approach; However, my code of using currying works but becomes an issue with 'addTogether(5)(7);'
Issue ->
I get the returned value of 12 but doesn't get approved in the code challenge.
I did originally return the value inside the sum function but the challenge required the sum value to be returned in addTogether function, which I did so now it resulting in the following
addTogether(2,3); // now working
addTogether(5)(7); // NOT working
addTogether(23, 30); // now working
Is there something I'm doing wrong that's resulting in the test case failing even though the correct value is returned?
let val = 0;
function sum(a, b) {
val = a + b;
}
function sumTwoAnd(sumFunc) {
return function addTogether(...params) {
let numsArr = [...params];
const res = numsArr.every(el => typeof el === 'number');
if (res === false) return;
if (numsArr.length >= sumFunc.length) {
sumFunc(...numsArr);
} else {
return function(...args2) {
let newArr = numsArr.concat(args2);
addTogether(...newArr);
}
}
console.log(val);
return val;
}
}
let addTogether = sumTwoAnd(sum);
addTogether(2,3);
addTogether(5)(7);
addTogether(23, 30);
Figure 1
Shows how I can get 'test(5)(7)' the second parameter from the function
function test() {
const [f, s] = arguments;
console.log(f, s)
if (s === undefined) {
return s => test(f, s)
}
}
test(23, 30);
test(5)(7);
You declared addTogether using let, so the declaration won't be hoisted above the point where it was defined. This is making your recursive call in the else statement fail, since addTogether() doesn't exist that far up.
You might want to extract the function you're returning in sumTwoAnd() as a separate function definition, so it can freely call itself, similar to your Figure 1 example.
Or you can call sumTwoAnd() instead to regain the function, then pass newArr to said function.
Instead of calling the function I have now returned it...
return addTogether(...newArr);
This now works :)
onceCopy function (testFunc) {
const copyFunc = (a) => {
const copyFunc2 = (b) => {
return testFunc(a);
};
return copyFunc2;
};
return copyFunc;
};
So the function returns the inner function upon first invocation.
Then returns the inner function of the inner function of the second invocation.
Then the second inner function (third invocation) actually returns the passed argument in the parent function and only invokes it with the character we gave it on the second invocation.
Ideally I want to achieve what I'm achieving over many invocations after only the first one if that makes sense.
Edit: Yes sorry, _.once.
Edit: so first invocation onceCopy SHOULD hold a copy of the Func passed
Second invocation SHOULD trigger the copy and gives an ouput
Third invocation SHOULD give the result of the second invocation so should the fourth, fifth, sixth and so on...
My function does do this, but on the second invocation it stores a function (copyFunc2) again, but I just made that because I need somewhere to store "a".
so like we have
function multiplyBy3 (a) {return a*3}
and then once copy stores a copy of multiplyBy3
const actualFunction = onceCopy(multiplyBy3)
then upon second and third invocation what I want
actualFunction(1) = 3
actualFunction(66) = 3
so the passed function ONLY RUNS ONCE
Cant explain more than this, its in the lodash docs.
I'm not familiar with the function you're trying to reimplement, so feel free to correct me if I misunderstood. To wrap a function and ensure it's only called once you don't need multiple nested wrappings, only one with some state.
You need to keep track of whether you already have a result to return (hasResult) and if so, what that result is (result). Keeping these two variables separate allows you to cover the case when result is undefined while keeping the code easy to read and understand.
function once(wrappedFunction) {
let hasResult = false;
let result;
return (...args) => {
if (hasResult) {
return result;
}
result = wrappedFunction.apply(this, args);
hasResult = true;
return result;
}
}
// An example function to wrap
function multiply(a, b) {
return a * b;
}
const demoFunction = once(multiply)
console.log(demoFunction(1, 2)); // 2
console.log(demoFunction(3, 4)); // 2
console.log(demoFunction(5, 6)); // 2
Is this what you were looking for?
The initial function return is kept on subsequent calls. I used a second variable called in case the first call returns undefined, which should also be returned on subsequent calls.
const once = (onceFn) => {
let called;
let value;
return (...args) => {
if (called) return value;
called = true;
return (value = onceFn(...args));
};
};
function multiplyBy3(a) {
return a * 3;
}
const fn = once(multiplyBy3);
console.log(fn(3)); // 9
console.log(fn(66)); // 9
After calling the function for the 1st time, and getting the result, create a new function that returns the result, and use it whenever the wrapped function is called:
const once = fn => {
let func
return (...args) => {
if(func) return func()
const result = fn(...args)
func = () => result
return result
}
}
const multiply = (a, b) => a * b
const demoFunction = once(multiply)
console.log(demoFunction(1, 2)); // 2
console.log(demoFunction(3, 4)); // 2
console.log(demoFunction(5, 6)); // 2
I have a question regarding curry function..
I know that if I have this simple curry function:
const greeting = (greet) => {
return (name) => {
return `${greet} ${name}`;
};
};
I can call greeting('Hello')('John') and it will return Hello John.
Is there a way to make it flexible say between 1 parameter and 2 parameters, ex: with
the above greeting function, is there a way for me to call greeting('Hello') and greeting('Hello')('John') and it will return Hello and Hello John respectively?
I know that I can do it with greeting('Hello')() and greeting('Hello')('John') but I was just trying to avoid breaking changes because I already have a greeting method and want to extend it using curry function, so I want it to also accept greeting('Hello') without the extra () at the end...
thanks
I can think of only one option that works by coercing the curried function into a string. This won't change the return value but it will allow you to get the result you want depending on context.
const greeting = greet => Object.defineProperties(
name => `${greet} ${name}`, // curried
{
toString: {
value: () => greet,
},
valueOf: {
value: () => greet
}
}
)
console.log(typeof greeting("Hello")) // function, not string
console.log(`${greeting("Hello")}`) // note the string context
console.log(`${greeting("Hello")("World")}`)
If you need the return value to actually toggle between a function and a string however, the answer is no.
In order for greeting("Hello")("John") to return a string, greeting("Hello") must return a function.
There is no way to tell within greeting() how the curried function is going to be called so you cannot detect whether or not to return a function or a string.
Think of it this way, greeting("Hello")("John") is just a short version of...
const fn = greeting("Hello")
// later or maybe never...
fn("John")
You simply don't know how, when or even if that curried function will be called.
Is there a way? Sure. But why? because won't that be "un-currying" it? And you will have to modify the function of-course.
You can always do something like this just get the output your asked for:
const greeting = (greet) => {
const split = greet.split(" ");
if(split.length > 1)
return `${split[0]} ${split[1]}`;
else return (name) => {
return `${greet} ${name}`;
};
};
If you use a helper function for currying, you can get a similar behavior automatically. For example, take the implementation at javascript.info/currying-partials
function curry(func) {
return function curried(...args) {
if (args.length >= func.length) {
return func.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
}
}
};
}
You can define
const greeting = curry((greet, name) => `${greet} ${name}`)
and call
greeting("Hello", "John")
or
greeting("Hello")("John")
I have been looking at this code for sometime now, trying to understand what it does but I can't really get my head around it. I need help with understanding what this function actually does
function element(array, gen) {
if(gen === undefined) {
gen = fromTo(
0,
array.length
);
}
return function() {
var index = gen();
if(index !== undefined) {
return array[index];
}
};
}
function concat(...gens) {
var next = element(gens),
gen = next();
return function recur() {
var value = gen();
if(value === undefined) {
gen = next();
if(gen !== undefined) {
return recur();
}
}
return value;
};
}
element is not a javascript built-in which means it must be defined elsewhere. Without knowing its function, it is impossible to say exactly what is happening, but here is what I can tell you.
concat takes n arguments of the same type. Without knowing what element does I can't tell you what type that is, but it can take as many as you need to give it. That is what the spread operator ... is telling you.
It returns a function that takes 0 arguments. When called, it continues to call itself checking if the return value of gen() is defined, if it is not, it changes gen to be the return value of next() and calls gen() again. It repeats this process until the return value of gen() is defined, and then returns that value.
Using it would look something like this.
var recur = concat(a,b,c,d,e); // can take any number of arguments of the same type
var someValue = recur(); // calls itself until it has a value to return
console.log(someValue); // use the value
I am having multiple problems with this function. It's part of a bonus question for a Data Structures and Algorithms class and I've invested so much time in this one problem, that I'd really like to get it to work and understand what's going on.
There is one main problem, which has caused several little ones...this problem's name is JavaScript. We've never programmed in JavaScript before, but for some reason we have to use it.
The function has to pass tests (this one and fibonacci), which are structured like this:
var fn = (n) => 2 * n
var m_fn = memoize(fn)
expect(m_fn(18)).to.equal(fn(18))
So I have to pass the function I want to memoize as a parameter of the memoize function and the memoize function has to return a function. I am not allowed to do it any other way.
I did all of the reading and researched the memoize function, but all of the implementations take a different approach.
Basically, I understand what I have to do, but I don't quite understand HOW. I know what the memoize function should do, but I don't understand how to adjust the original function using my memoize function. This is what I have so far/what I don't have:
I know it's wrong. But I think I'm missing something major. I am supposed to return a function, but I am returning values...
In the test, it's writen var m_fn = memoize(fn), so the memoize function passes fn, then returns a new function, but in my memoize, I am returning values for fn(n), so I AM doing something wrong...
/**
* Creates a memoized version of the function fn. It is assumed that fn is a referentially transparent
* function.
* #param {function} fn Some referentially transparent function that takes a basic datatype (i.e. number / string)
* #returns {function} A new function that is the memoized version of fn. It never calculates the result of
* a function twice.
*/
memoize: (fn) => { //here we enter the function that we want to memoize
var memory = []; //we need to create an array to hold the previously calculated values, length n (parameter of fn)
if(this.n > memory.length){ //Check to see if this particular value is in the array already.
return memory[this.n]; //How do I access the integer parameter that was passed through fn though? Is this correct?
} else{ // if not, we want to save it and return it
var result = fn(this.n);
memory.push(result);
return result;
}
}
Indeed, you need to return a function.
Secondly, an array is not the ideal structure for memory, because it takes linear time to find an argument value in it. I would suggest to use a Map for this, which is ideal for such purposes. It has has(), get() and set() methods which run in near-constant time:
function memoize(fn) {
var memory = new Map();
return function(arg) {
if (memory.has(arg)) {
console.log('using memory');
return memory.get(arg);
} else {
var result = fn(arg);
memory.set(arg, result);
return result;
}
};
}
var fn = (n) => 2 * n
var m_fn = memoize(fn)
console.log(fn(18));
console.log(m_fn(18));
console.log(m_fn(18)); // outputs also "using memory"
You could use a Map as memory.
var memoize = f =>
(map => v => (!map.has(v) && map.set(v, f(v)), map.get(v)))(new Map),
fn = (n) => 2 * n,
m_fn = memoize(fn);
console.log(m_fn(18), fn(18));
Looking at your code and in-code comments and assuming I'm interpreting correctly, you're really close to the solution. As you've said in the question, you need to return a function that returns the values rather than returning the values.
See comments for explanation:
function memoize(f) {
// An array in which to remember objects with the input arg and result
var memory = [];
// This is the function that will use that array; this is the
// return value of memoize
return function(arg) {
// This code runs when the function returned by memoize is called
// It's *here* that we want to process the argument, check the `memory`
// array, call `f` if necessary, etc.
var entry;
// See if we have a previously-saved result for `arg`
var entry = memory.find(entry => entry.arg === arg);
if (!entry) {
// No -- call `fn`, remember the `arg` and result in an object
// we store in memory``
entry = {arg, result: f(arg)};
memory.push(entry);
}
// We have it (now), return the result
return entry.result;
};
}
function fn(arg) {
console.log("fn called with " + arg);
return 2 * arg;
}
var m_fn = memoize(fn);
console.log(m_fn(18));
console.log(m_fn(18));
console.log(m_fn(20));
console.log(m_fn(20));
Note: There was an arrow function in your code, so I've assumed it's okay to use ES2015 features above. There's not actually very much of it, though, just the arrow function passed to memory.find, the assumption that Array#find will be available, and the syntax used to create the entry object (in ES5 we' need entry = {arg: arg, result: f(arg)} instead).
Note that if we can assume that arg will be a string or number or other value that can reliably be converted to string, we can use an object to store the data rather than an array.
And actually, given this is ES2015, we can use a Map:
function memoize(f) {
// An Map in which to remember objects with the input arg and result
const memory = new Map();
// This is the function that will use that array; this is the
// return value of memoize
return function(arg) {
// This code runs when the function returned by memoize is called
// It's *here* that we want to process the argument, check the `memory`
// array, call `f` if necessary, etc.
let result;
// See if we have a previously-saved result for `arg`
if (!memory.has(arg)) {
// No -- call `fn`, remember the `arg` and result in an object
// we store in memory``
result = f(arg);
memory.set(arg, result);
} else {
// Yes, get it
result = memory.get(arg);
}
// We have it (now), return the result
return result;
};
}
function fn(arg) {
console.log("fn called with " + arg);
return 2 * arg;
}
var m_fn = memoize(fn);
console.log(m_fn(18));
console.log(m_fn(18));
console.log(m_fn(20));
console.log(m_fn(20));
Note that in both cases, I've written the code verbosely to allow for comments and easy comprehension. The ES2015 version with Map, in particular, can be quite a lot shorter.