Ash*_*ain 6 javascript performance set data-structures ecmascript-6
ES6 有一个新的 Set 数据结构,用于存储唯一对象的集合。然而,它基于对象引用而不是值比较。据我所知,这使得在没有字符串化的情况下不可能有一组数字。
例如,在 Chrome 的控制台中输入(需要 Chrome 38+):
> var s = new Set();
< undefined
> s.add([2, 3]);
< Set {[2, 3]}
> s.has([2, 3])
< false <--- was hoping for 'true'
Run Code Online (Sandbox Code Playgroud)
这似乎是设计使然:因为我传递了一个不同的[2, 3]to数组has(),它返回 false,因为虽然内容相同但它只查看对象引用,并且我分配了一个新的不同数组来传递 to has()。我需要存储对我传递给与add()检查的原始数组的引用has(),但这并不总是可能的。例如,如果数字对代表坐标,我可能需要检查集合是否有[obj.x, obj.y],但这将始终返回 false,因为它分配了一个新数组。
解决方法是将数组和键字符串化为“2, 3”之类的字符串。然而,在像游戏引擎这样对性能敏感的东西中,如果每个集合访问都需要进行字符串分配并转换和连接数字字符串,那就很不幸了。
ES6 是否提供了任何功能来解决这个问题而无需进行字符串化,或者 ES7 是否有任何即将推出的功能也可以提供帮助?
对于计算密集型任务来说,它并不是完美的最佳选择,但您可以使用模板文字连接字符串,以获得更惯用的方法,但仍保持效率,例如
set.add(`${x}_${y}`);
Run Code Online (Sandbox Code Playgroud)
和检索:
set.get(`${i}_${j}`);
Run Code Online (Sandbox Code Playgroud)
(请注意,我故意避免将其用作,分隔符,因为它在某些领域(例如金融)可能会令人困惑)。
如果您知道边界,可以做的另一件事是抓住第一个维度的宽度来展平数组,例如
set.get(x+y*width);
Run Code Online (Sandbox Code Playgroud)
或者,如果您一般处理较小的数字(不超过 10,000)并且不知道最大宽度是多少,则可以使用任意非常大的数字。这稍微不太理想,但仍然比字符串连接更好:
set.get(x+y*Math.floor(Math.sqrt(Number.MAX_SAFE_INTEGER)));
Run Code Online (Sandbox Code Playgroud)
同样,这些都不是完美的解决方案,因为它们不适用于x*y可能超过的非常大的数字Number.MAX_SAFE_INTEGER,但它们是您工具箱中的一些东西,不需要知道固定的数组大小。
[这里超级晚了,但由于 ES7 毕竟没有修复问题,而且我注意到如果其他人正在权衡利弊,则没有特别提到这一点,有两种方法(第一种明确无法解决,第二种可能可能)]
正如您所指出的,[2, 3] === [2, 3]这false意味着您不能像这样使用Set ;然而,Set真的是您的最佳选择吗?
您可能会发现使用这样的两级数据结构对您来说会更好
var o = {};
function add(o, x, y) {
if (!o[x]) o[x] = {};
o[x][y] = true;
}
function has(o, x, y) {
return !!(o[x] && o[x][y]);
}
function del(o, x, y) {
if (!o[x]) return;
delete o[x][y];
// maybe delete `o[x]` if keys.length === 0
}
Run Code Online (Sandbox Code Playgroud)
如果你想使用ES6 ,你可以使用指向Sets 的Map来实现类似的结构
| 归档时间: |
|
| 查看次数: |
2736 次 |
| 最近记录: |