有人能给我一个undercore.js _.memoize()的例子吗?
优选使用hashFunction,甚至更优选使用coffeescript?
以下是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非常陌生,也欢迎任何使这些代码更具惯用性的帮助。
答案 0 :(得分:17)
此处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"
我还为了紧凑而重新安排了一些事情,我在firstDenomination
之外移动cc
以简化cc
,而我在那里;我的firstDenomination
是否比你的更好是一个品味问题,我偏向于使用a switch
实现一个简单的查找表,但YMMV。
备忘录版本说“211次cc版”,演示:http://jsfiddle.net/ambiguous/FZsJU/
非记忆版本说“8141次cc版”,演示:http://jsfiddle.net/ambiguous/Xn944/
因此,非记忆版本会更频繁地调用cc
~40倍。根据散列函数的计算开销(我的足以用于演示目的但未完全优化)以及高速缓存查找的开销,memoization可能是值得的,也可能是不值得的。这是memoizing时要问的标准问题:缓存是否比缓存计算更快?
如果我们看一下_.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));
};
};
然后你可以看到它是如何工作的以及如何使用hasher
。 memo
对象用作缓存,hasher
用于将memoized函数的参数转换为memo
中的键;如果我们找到密钥,那么我们可以立即返回缓存的值,否则我们计算它(可能)缓慢的方式,缓存它,然后返回它。