在Javascript中设置的数字对

时间:2014-09-21 13:06:41

标签: javascript performance data-structures set 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'

这似乎是设计上的:因为我将不同的数组[2, 3]传递给has(),所以它返回false,因为虽然内容相同,但它只是看起来在对象引用,我分配了一个新的不同的数组传递给has()。我需要存储对传递给add()的原始数组的引用,以便与has()一起检查,但这并不总是可行的。例如,如果数字对代表坐标,我可能需要检查该集合是否具有[obj.x, obj.y],但由于它分配了一个新数组,因此总是返回false。

解决方法是将数组和键键入字符串,例如&#34; 2,3&#34;代替。然而,对于像游戏引擎这样对性能敏感的东西,如果每个set访问都需要进行字符串分配并转换和连接数字字符串,这是很不幸的。

ES6是否提供任何功能来解决此问题而无需进行字符串化,或者ES7是否有任何功能可以提供帮助?

3 个答案:

答案 0 :(得分:3)

正如您所指出的那样[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
}

如果您想使用 ES6

,您可以使用指向 Map 执行类似的结构

答案 1 :(得分:0)

  

ES7有什么功能可以提供帮助吗?

ECMAScript 7中有一项建议添加Value Objects。基本上,它是一个新的不可变数据类型,其中相同的值对象按值进行比较,而不是通过引用进行比较。

根据实施的价值对象类型和/或if custom ones can be defined,它们可能会解决此问题。

答案 2 :(得分:0)

这里超级晚,但是由于ES7毕竟还没有解决问题,而且我注意到如果其他人在权衡利弊时没有特别提及,则有两种方法(第一种方法不能解决,第二种可能): / p>

对于执行大量计算的任务而言,它并不是最佳选择,但是您可以使用使用模板文字的串联字符串来实现可表达性,例如

set.add(`${x}_${y}`);

和检索:

set.get(`${i}_${j}`);

(请注意,我故意避免使用,作为分隔符,因为在某些领域(例如金融领域)可能会造成混淆)。

可以做的另一件事是,如果知道边界,例如抓住第一维的宽度来展平数组。

set.get(x+y*width);

或者如果您通常使用较小的数字(不超过10,000s)并且不知道最大宽度是多少,则可以使用任意的非常大的数字。最佳效果稍差一些,但仍比字符串concat好:

set.get(x+y*Math.floor(Math.sqrt(Number.MAX_SAFE_INTEGER)));

同样,这些并不是完美的解决方案,因为它们无法处理x*y可能超过Number.MAX_SAFE_INTEGER的大量数字,但是它们是工具箱中的某些东西,不需要知道固定的数组大小。