摘要:是否有更快的方式来散列对象而不是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)时间来查找值的标识符?
答案 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
永远不会返回假名值null
,undefined
,{ {1}},false
,NaN
,0
)。更安全的代码行看起来像:
""
答案 2 :(得分:1)
如果您只需要记忆对象,那么为对象分配一些唯一ID是有意义的。
var gID = 0;
function createNode() {
var obj = ...
obj.id = (++gID).toString();
}
并将obj.id
个memo
用作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()