Only allowing a function to run n times with wrapper function
Asked Answered
P

3

5

I need to make a wrapper function to invoke a function multiply with a given number num of times to allow the multiply to execute. nTimes(num,2) Then assign to runTwice -- runTwice can be any function that invoke the nTimes function which given a different num input--

In my case, for simplicity, I am only allowing it to run 2 times num=2 If we run the runTwice function the first time and the second time it will return the result of multiply function calculated with the inputs for multiply. Any invocation after the second time will not run the multiply function but will return the latest result of the multiply function.

Here is my implementation using an object to keep track of how many times we have execute the function, the max number allowed to execute and the latest result of multiply

 'use strict'
//use a counter object to keep track of counts, max number allowed to run and latest result rendered
let counter = {
    count:0,
    max: 0,
    lastResult: 0
};

let multiply = function(a,b){
    if(this.count<this.max){
        this.count++;
        this.lastResult = a*b;
        return a*b;
    }else{
        return this.lastResult;
    }
}

// bind the multiply function to the counter object
multiply = multiply.bind(counter);

let nTimes=function(num,fn){
    this.max = num;
    return fn;
};

// here the nTimes is only executed ONE time, we will also bind it with the counter object
let runTwice = nTimes.call(counter,3,multiply);

console.log(runTwice(1,3)); // 3
console.log(runTwice(2,3)); // 6
console.log(runTwice(3,3)); // 6
console.log(runTwice(4,3)); // 6

Note that I have altered the simple multiply quite a bit and bind it the counterobject to make it work. Also using call on nTimes to bind counter object.

What can I do to implement the same result with a wrapper function but less alteration to the simple multiply function?

Let's say the multiply function is very simple:

let multiply = function(a,b){ return a*b };
Pilfer answered 23/2, 2019 at 16:21 Comment(0)
S
2

Nina's answer is great. Here's an alternative, with code that might look slightly easier to read:

function multiply(a, b) {
  return a * b;
}

function executeMaxTimes(max, fn) {
  let counter = 0, lastResult;
  return (...args) => counter++ < max 
    ? lastResult = fn(...args) 
    : lastResult;
}

const multiplyMaxTwice = executeMaxTimes(2, multiply);

console.log(multiplyMaxTwice(1, 3)); // 3
console.log(multiplyMaxTwice(2, 3)); // 6
console.log(multiplyMaxTwice(3, 3)); // 6
console.log(multiplyMaxTwice(4, 3)); // 6
Sid answered 23/2, 2019 at 16:53 Comment(6)
Thanks! I am trying to understand this. So when we assign to multiplyMaxTwice, the executeMaxTimes is executed, only for one time. Then when every time we invoke the multiplyMaxTwice the returned function will be invoked that makes the counter increase each time we invoked. Is this the logic?Pilfer
@MingHuang Actually, check my last edit for a slightly clearer version (counter defined as a normal variable). Basically, executeMaxTimes returns a function that compares counter with max and return either the result of fn, or the last result registered (lastResult). So, every time multiplyMaxTwice is called, that returned function checks that condition with an increased counter. First time counter is 0 (which is < max) so it returns the result of fn (multiply here), then 1 (same), then 2 which is not < max so lastResult is returned, same for subsequent calls.Sid
changing value inside the ternary statement or if statement is very cool trick. I have never use it like that before. One more question, it seems the lastResult in your code was never declared but you can just assign value to it. What is happening there?Pilfer
@Sid You never declare lastResult this will fail strict modeNonnah
@MingHuang You're right (so is nick zoum), I actually forgot to declare it, sorry about that! Just edited the answer.Sid
Great, now I can go to my interview and hope they ask this question.Pilfer
V
3

You could use a closure over the count and the last value and check count and decrement and store the last result.

const
    multiply = (a, b) => a * b,
    maxCall = (fn, max, last) => (...args) => max && max-- ? last = fn(...args) : last,
    mult3times = maxCall(multiply, 3);

console.log(mult3times(2, 3));
console.log(mult3times(3, 4));
console.log(mult3times(4, 5));
console.log(mult3times(5, 6));
console.log(mult3times(6, 7));
Vacation answered 23/2, 2019 at 16:37 Comment(2)
The code works but I have a hard time understanding what is last = max && max-- doing??Pilfer
this is part of the check of the conditional (ternary) operator ?:, where max is checked and if not zero, then max is decremented and the result of the function call assigned. if max is zero, then last is assigned and returned.Vacation
S
2

Nina's answer is great. Here's an alternative, with code that might look slightly easier to read:

function multiply(a, b) {
  return a * b;
}

function executeMaxTimes(max, fn) {
  let counter = 0, lastResult;
  return (...args) => counter++ < max 
    ? lastResult = fn(...args) 
    : lastResult;
}

const multiplyMaxTwice = executeMaxTimes(2, multiply);

console.log(multiplyMaxTwice(1, 3)); // 3
console.log(multiplyMaxTwice(2, 3)); // 6
console.log(multiplyMaxTwice(3, 3)); // 6
console.log(multiplyMaxTwice(4, 3)); // 6
Sid answered 23/2, 2019 at 16:53 Comment(6)
Thanks! I am trying to understand this. So when we assign to multiplyMaxTwice, the executeMaxTimes is executed, only for one time. Then when every time we invoke the multiplyMaxTwice the returned function will be invoked that makes the counter increase each time we invoked. Is this the logic?Pilfer
@MingHuang Actually, check my last edit for a slightly clearer version (counter defined as a normal variable). Basically, executeMaxTimes returns a function that compares counter with max and return either the result of fn, or the last result registered (lastResult). So, every time multiplyMaxTwice is called, that returned function checks that condition with an increased counter. First time counter is 0 (which is < max) so it returns the result of fn (multiply here), then 1 (same), then 2 which is not < max so lastResult is returned, same for subsequent calls.Sid
changing value inside the ternary statement or if statement is very cool trick. I have never use it like that before. One more question, it seems the lastResult in your code was never declared but you can just assign value to it. What is happening there?Pilfer
@Sid You never declare lastResult this will fail strict modeNonnah
@MingHuang You're right (so is nick zoum), I actually forgot to declare it, sorry about that! Just edited the answer.Sid
Great, now I can go to my interview and hope they ask this question.Pilfer
N
1

Seeing how both Nina and Jeto have answered your question, here is a simple and similar way to do it that also keeps a history of all the results in case you want to get them at a later time.

function multiply(a, b) {
  return a * b;
}

function runMaxNTimes(num, callBack) {
  var results = new Array(num);
  var callTimes = 0;
  return function(...params) {
    return results.length > callTimes ?
      results[callTimes++] = callBack(...params) :
      results[callTimes - 1];
  };
}

var runTwice = runMaxNTimes(2, multiply);

console.log(runTwice(1, 3)); // 3
console.log(runTwice(2, 3)); // 6
console.log(runTwice(3, 3)); // 6
console.log(runTwice(4, 3)); // 6
Nonnah answered 23/2, 2019 at 16:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.