Javascript 中的一组数字

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 是否有任何即将推出的功能也可以提供帮助?

rob*_*b2d 5

对于计算密集型任务来说,它并不是完美的最佳选择,但您可以使用模板文字连接字符串,以获得更惯用的方法,但仍保持效率,例如

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 毕竟没有修复问题,而且我注意到如果其他人正在权衡利弊,则没有特别提到这一点,有两种方法(第一种明确无法解决,第二种可能可能)]


Pau*_* S. 4

正如您所指出的,[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来实现类似的结构