【问题标题】:example of underscore.js _.memoize() in action?underscore.js _.memoize() 的例子?
【发布时间】:2012-04-27 10:25:25
【问题描述】:

谁能给我一个 underscore.js _.memoize() 的例子吗?

最好使用hashFunction,甚至最好用coffeescript?

这里是来自咖啡脚本中 SICP 的可爱变化计数功能的略微修改版本:

countChange = (amount)->

  cc = (amount, kindsOfCoins)->

    firstDenomination = (kindsOfCoins)->
      switch kindsOfCoins
        when 1 then 1
        when 2 then 5
        when 3 then 10
        when 4 then 25

    if amount is 0 then 1
    else if amount < 0 or kindsOfCoins is 0 then 0
    else 
      (cc amount, (kindsOfCoins - 1)) + 
      (cc (amount - firstDenomination(kindsOfCoins)), kindsOfCoins)

  cc amount*100, 4


console.log "Ways to make change for $0.85: " + countChange(.85)

例如,我如何使用下划线的 _.memoize() ?

非常感谢!

ps .. 另外,请不要犹豫,在函数编码方式上留下漏洞。我对 coffeescript 很陌生,也欢迎任何关于使该代码更惯用的帮助。

【问题讨论】:

    标签: javascript coffeescript underscore.js sicp memoization


    【解决方案1】:

    这里memoize 的一个用途是减少对内部cc 函数的调用次数:

    n = 0
    countChange = (amount)->
      firstDenomination = (kindsOfCoins) ->
        [1, 5, 10, 25][kindsOfCoins - 1]
    
      cc = (amount, kindsOfCoins)->
        ++n # This is just a simple counter for demonstration purposes
        return 1 if amount is 0
        return 0 if amount < 0 or kindsOfCoins is 0
        (cc amount, (kindsOfCoins - 1)) +
          (cc (amount - firstDenomination(kindsOfCoins)), kindsOfCoins)
    
      cc = _.memoize cc, (a,k) -> "#{a},#{k}"
    
      cc amount*100, 4
    
    console.log "Ways to make change for $0.85: #{countChange(.85)}"
    ​console.log "#{n} iterations of cc"
    

    为了紧凑,我还稍微重新安排了一些东西,我在cc 之外移动了firstDenomination 以简化cc,而我在那里;我的​​​​​​​​​​​​firstDenomination是否比你的更好是一个品味问题,我对使用@987654331有偏见@ 实现一个简单的查找表但 YMMV。

    记忆版写着“cc的211次迭代”,demo:http://jsfiddle.net/ambiguous/FZsJU/

    一个非记忆版本说“cc 的 8141 次迭代”,演示:http://jsfiddle.net/ambiguous/Xn944/

    因此,非记忆版本调用cc 的频率大约增加了 40 倍。根据散列函数的计算开销(我的足以用于演示目的,但没有完全优化)和缓存查找的开销,记忆可能值得也可能不值得。这是记忆时要问的标准问题:缓存比缓存计算快吗?

    如果我们看一下_.memoize的实现:

    // Memoize an expensive function by storing its results.
    _.memoize = function(func, hasher) {
      var memo = {};
      hasher || (hasher = _.identity);
      return function() {
        var key = hasher.apply(this, arguments);
        return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
      };
    };
    

    然后您可以看到它是如何工作的以及如何使用hashermemo对象用作缓存,hasher用于将memoized函数的参数转换为memo中的key;如果我们找到键,那么我们可以立即返回缓存的值,否则我们以(可能)慢的方式计算它,缓存它,然后返回它。

    【讨论】:

    • 哇!全面的出色答案。非常感谢所有的细节和重组。都非常有见地。
    • 快速跟进问:在hashFunction中为什么要返回这个:“#{a},#{k}”,而不是这个:[a,k]
    • @James:哈希函数必须返回一些可以用作memo 对象中的键的东西,最好明确说明转换,而不是依靠浏览器对@987654340 做一些明智的事情@.
    猜你喜欢
    • 2012-05-10
    • 1970-01-01
    • 1970-01-01
    • 2014-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-11
    • 2018-09-25
    相关资源
    最近更新 更多