Memoize函数传递函数并返回函数JavaScript

时间:2016-10-30 11:45:17

标签: javascript parameters memoization

我在使用此功能时遇到了多个问题。这是数据结构和算法课程的奖金问题的一部分,我在这一个问题上花了很多时间,我真的很想让它工作并理解发生了什么。

有一个主要问题,导致了几个小问题......这个问题的名字是JavaScript。我们以前从未在JavaScript中编程,但出于某种原因我们必须使用它。

该函数必须通过测试(这个和斐波那契),结构如下:

var fn = (n) => 2 * n
var m_fn = memoize(fn)
expect(m_fn(18)).to.equal(fn(18))

所以我必须传递我想要memoize的函数作为memoize函数的参数,memoize函数必须返回一个函数。我不允许以任何其他方式这样做。

我完成了所有阅读并研究了memoize函数,但所有实现都采用了不同的方法。

基本上,我明白我必须做什么,但我不太明白。我知道memoize函数应该做什么,但我不明白如何使用memoize函数调整原始函数。这就是我到目前为止/我没有的东西:

我知道这是错的。但我想我错过了一些重要的东西。我应该返回一个函数,但我正在返回值......

在测试中,它是写入var m_fn = memoize(fn),所以memoize函数传递fn,然后返回一个新函数,但在我的memoize中,我返回fn(n)的值,所以我在做某事错...

/**
* 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;
 } 

}

3 个答案:

答案 0 :(得分:2)

确实,您需要返回一个函数。

其次,数组不是[[FunctionLocation]]的理想结构,因为它需要线性时间来查找其中的参数值。我建议使用Map来实现这一目的。它有memoryhas()get()方法,可以在接近恒定的时间内运行:



set()




答案 1 :(得分:1)

您可以使用Map作为记忆。



jupyter python




答案 2 :(得分:0)

查看您的代码和代码内注释,并假设我正确地解释,您真的非常接近解决方案。正如您在问题中所说,您需要返回一个函数,它返回值而不是返回值。

请参阅注释以获取解释:



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));




注意:您的代码中有一个箭头功能,所以我认为可以使用上面的ES2015功能。但实际上并不是很多,只是传递给memory.find的箭头函数,假设Array#find可用,以及用于创建条目对象的语法(在ES5中)我们需要entry = {arg: arg, result: f(arg)}代替。)

请注意,如果我们可以假设arg将是一个字符串或数字或其他值可以可靠地转换为字符串,我们可以使用一个对象来存储数据而不是数组。

实际上,鉴于这是ES2015,我们可以使用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));




请注意,在这两种情况下,我都会详细地编写代码,以便进行评论和轻松理解。特别是Map的ES2015版本可以相当更短。