djf*_*dev 9 javascript arrays set ecmascript-6
有一种简单的方法可以验证ES6 Set是否包含特定数组的值?我想要一个不需要我使用引用的解决方案:
var set = new Set();
var array = [1, 2];
set.add(array);
set.has(array); // true
set.add([3, 4]);
set.has([3, 4]); // false
Run Code Online (Sandbox Code Playgroud)
到目前为止,我的解决方案是将所有内容存储为字符串,但这很烦人:
set.add([3, 4].toString());
set.has([3, 4].toString()); // true
Run Code Online (Sandbox Code Playgroud)
Ale*_*ara 16
不,那里没有.
A Set适用于对象和基元,可用于防止相同的基元并重新添加相同的对象实例.
每个数组都是它们自己的对象,因此您实际上可以添加两个具有相同值的不同数组.
var set = new Set();
set.add([3, 4]);
set.add([3, 4]);
console.log(set.size);//2
Run Code Online (Sandbox Code Playgroud)
此外,没有什么可以阻止对象在集合中被更改一次.
var set = new Set();
var a1 = [3, 4];
var a2 = [3, 4];
set.add(a1);
set.add(a2);
a2.push(5);
for (let a of set) {
console.log(a);
}
//Outputs:
// [3, 4]
// [3, 4, 5]
Run Code Online (Sandbox Code Playgroud)
集合没有用于检查集合中对象值的机制.由于对象的值可能随时发生变化,因此它不会比简单地循环遍历它们更有效.
您正在寻找的功能已经在各种ECMAScript提案中被提及,但它似乎不会很快到来.
代表太低,无法添加评论,因此我将其添加为此处的答案。提前对文字墙表示歉意。
我喜欢 CTS_AE 的回答,并想采取同样的路线。但是,有一点需要注意,那就是数组如何放入 String 中。
let memory = {};
memory[[1,2,3]] = "123";
console.log(memory[[1,2,3]]); // "123"
console.log([1,2,3].toString(); // "1,2,3"
console.log(memory["1,2,3"]); // "123"
Run Code Online (Sandbox Code Playgroud)
现在,如果您知道您放入的内容完全是数组,那么这不会是一个问题......或者会吗?
MDN 关于 Array.prototype.toString() 说
对于 Array 对象,toString 方法连接数组并返回一个字符串,其中包含以逗号分隔的每个数组元素。
这带来了两个大问题:
array与索引 via 相同array.toSring()toString()是递归的,嵌套数组最终会被字符串化为与单级数组相同的格式。let memory = {};
memory[[1,2,3]] = "123";
console.log(memory[[1,2,3]]); // "123"
console.log(memory["1,2,3"]); // "123"
console.log(memory[[[1],[2],[3]]]); // "123"
console.log(memory[[[[1],2],3]]); // "123"
Run Code Online (Sandbox Code Playgroud)
...而这样的例子不胜枚举。不难看出这些问题何时会真正破坏您的项目。不久前我尝试记忆时遇到了这样的问题
function doSomeStuff(string, sourceIdxs, targetIdxs) {
if (memo[[string, sourceIdxs, targetIdxs]])
return memo[[string, sourceIdxs, targetIdxs]];
// ...
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,例如["foo", [1, 3, 5], [6, 10]]和["foo", [1, 3], [5, 6, 10]]指向相同的值,我最终覆盖了现有的值,有效地破坏了函数内存。
现在,在上述答案的具体情况下ArraySet,问题仍然存在。虽然您不介意用另一个“相同”密钥覆盖现有密钥,但最终可能会得到误报。
简单的方法是JSON.stringify()编写所有关键数据的“精确”字符串表示形式。
let memory = {};
memory[JSON.stringify([1,2,3])] = "123";
console.log(memory[JSON.stringify([1,2,3])]); // "123"
console.log(memory[JSON.stringify([[1],[2,3]])); // undefined
Run Code Online (Sandbox Code Playgroud)
这有助于消除误报......有点。其一,数组中的元素重叠不会出现问题。[[1,2],[3]]不再指向哪里[[1],[2,3]]。
然而,[1,2,3]并且"[1,2,3]"做到了。此外(在某些奇怪的情况下),数组元素可能包含[或]字符,这可能会使问题进一步复杂化。
你可能不关心这种情况。您的钥匙可能仍被妥善保管,这样的事情就不会发生。你甚至可能想要这样的行为。如果你愿意,那就去做吧。
好的:
ArraySet坏的:
JSON.stringify()相当慢。更简单、更快,同时仍然比旧解决方案有一些优势。
function toSepString(arr) { return arr.join("|") }
let memory = {};
memory[toSepString([[1,2],3])] = "123";
console.log(memory[toSepString([1,[2,3]])]); // undefined
Run Code Online (Sandbox Code Playgroud)
当然,现在这仅对“最外层”有帮助。
console.log(toSepString([1,[2,[3]]])); // "1|2,3"
console.log(toSepString([1,[[2],[[3]]]]); // "1|2,3"
Run Code Online (Sandbox Code Playgroud)
因此,如果您使用它,您需要确保键数组的特定元素在转换为字符串时不会变得模糊。
当然,您可以使该函数递归并"[", "]"在每个开头和结尾添加,本质上是复制JSON.stringify(). 我想这仍然比JSON.stringify()直接调用性能更高,但这需要测试。
好的:
坏的:
它不使用 a Set,但可以解决您的问题。
如果您想确保数组只能在集合中存在一次,并且需要即时查找,则可以通过滥用其键来使用哈希。他们不一定需要价值。如果可以让您晚上睡得更好,您可以将它们设置为undefined、到或其他值。true
灵感来源:javascript 搜索数组数组
制作包装纸有点诱人,但它也很简单,足以处理一项小工作。
const hash = {};
hash[[1, 2, 3]] = undefined;
hash[[3, 4]] = undefined;
hash[[3, 4]] = undefined;
console.log({hash});
console.log("hash has [3, 4]?", hash.hasOwnProperty([3, 4]));Run Code Online (Sandbox Code Playgroud)
对我来说,这会很好地工作,因为我正在检查集合中是否存在坐标。不幸的是,这stackoverflow似乎Set不能解决这个问题。
巧合的是,它似乎隐式解决了您不调用toString数组的问题,这似乎是在幕后进行的。我个人不关心hash.hasOwnProperty。
您甚至可以为您的代码编写一个包装器,例如:
class ArraySet extends Set {
add(arr) {
super.add(arr.toString());
}
has(arr) {
return super.has(arr.toString());
}
}
const arraySet = new ArraySet();
arraySet.add([1, 2]);
arraySet.add([3, 4]);
arraySet.add([3, 4]);
console.log("ArraySet has [3, 4]?", arraySet.has([3, 4]));Run Code Online (Sandbox Code Playgroud)