高效的对象参数的memoization

时间:2016-02-09 16:15:44

标签: javascript memoization

摘要:是否有更快的方式来散列对象而不是JSON.stringify

详细信息:我有一个Ruby和JavaScript库(NeatJSON),可以提供漂亮的JavaScript值打印。我最近解决了一个问题,即深度嵌套的对象使用基于被序列化的对象和缩进量的memoization导致O(n!)性能( n 是嵌套级别)。

在Ruby中,the fix非常简单,因为您可以通过唯一对象集的数组来索引哈希值:

build = ->(object,indent) do
  memoizer[[object,indent]] ||= <all the rest of the code>
end

但是,在JavaScript中,我无法通过另一个对象(以独特的方式)索引对象。在我在网上发现的几篇文章的引导下,我决定fix the problem一般地,在函数的完整参数集上使用JSON.stringify来创建用于记忆的唯一键:

function memoize(f){
  var memo  = {};
  var slice = Array.prototype.slice;
  return function(){
    var args = slice.call(arguments);
    var mkey = JSON.stringify(args);
    if (!(mkey in memo)) memo[mkey] = f.apply(this,args);
    return memo[mkey];
  }
}

function rawBuild(o,indent){ .. }
var build = memoize(rawBuild);

这是有效的,但是(a)它比我想要的慢一点,并且(b)对我和每个对象和值的执行(天真)序列化似乎非常低效(并且不优雅) #39;我要巧妙地序列化。序列化具有许多值的大对象的行为将在整个对象中存储每个唯一值(不仅仅是叶值)的字符串和格式化结果。

是否有一个现代的JavaScript技巧可以让我唯一地识别一个值?例如,某种方式访问​​内部ID,或以其他方式将复杂对象与唯一的整数相关联,这些整数需要花费O(1)时间来查找值的标识符?

3 个答案:

答案 0 :(得分:3)

如果您希望按身份(而不是按内容)记住您的对象,那么您将要使用专为此目的而设计的WeakMap。但是他们不会为原始价值观工作,所以你需要一个不同的解决方案来解决这些问题。

答案 1 :(得分:2)

使用@ Bergi建议的WeakMap我发现了Map,它允许使用任何值类型作为键(而不仅仅是对象)。因为我需要一个复合键 - 唯一地记忆在中传递的值的组合,缩进字符串 - 我创建了一个分层的memoization结构:

function memoizedBuild(){
  var memo = new Map;
  return function(value,indent){
    var byIndent=memo.get(value);
    if (!byIndent) memo.set(value,byIndent={});
    if (!byIndent[indent]) byIndent[indent] = rawBuild(value,indent);
    return byIndent[indent];
  }
}

在序列化大型270kB JSON对象时,事实证明这比memoization code I had been using快4倍。

请注意,在上面的代码中,我只能使用!byIndent[indent],因为我知道rawBuild永远不会返回假名值nullundefined,{ {1}},falseNaN0)。更安全的代码行看起来像:

""

答案 2 :(得分:1)

如果您只需要记忆对象,那么为对象分配一些唯一ID是有意义的。

var gID = 0;

function createNode() {
  var obj = ...
  obj.id = (++gID).toString();
}

并将obj.idmemo用作var gID = 0; var gUidSym = Symbol("uid"); function getUidOf(obj) { return obj[gUidSym] || (obj[gUidSym] = (++gID).toString()); } 集合中的键。

这将是最快和最不贪心的解决方案。

更新

如果您希望该id属性不与现有属性冲突 然后,您可以使用标准ES5.1 Object.createProperty()(具有一些唯一名称)创建不可枚举的属性,或使用ES6 symbols

import sys
import time
path= 'pc_path'
file = path + '\\' + 'test.txt'

files = open(file, 'w')
files.close()

def log(msg):
    time = time.time()
    filess = open(file, 'a')
    filess.write(msg)
    filess.close()

val = 10
val1 = 32
try:
    operazione = val + val1
    print('ok')
    print(operazione)
    msg = operazione
    log(msg)
except:
    sys.exit()