Javascript 如何检查两个 Map 对象是否相等?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35948335/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I check if two Map objects are equal?
提问by Luka
How can I check if two ES2015 Mapobjects have the same set of (key, value)
pairs?
如何检查两个ES2015 Map对象是否具有相同的(key, value)
对?
We can assume that all the keys and values are primitive datatypes.
我们可以假设所有的键和值都是原始数据类型。
One approach to solve this would be to take the map.entries()
, create array from it, then sort that array by keys. And do the same thing with the other map. And then loop through those two arrays to compare them. All this seams cumbersome and also very inefficient because of sorting (performance inefficiency) and because of making those arrays (memory inefficiency).
解决此问题的一种方法是获取map.entries()
, 从中创建数组,然后按键对该数组进行排序。对另一张地图做同样的事情。然后循环遍历这两个数组来比较它们。由于排序(性能效率低下)和制作这些数组(内存效率低下),所有这些接缝都很麻烦,而且效率也很低。
Does anybody have better idea?
有人有更好的主意吗?
回答by jfriend00
There is no "standard" or "built-in" way to do this. Conceptually, you just have to compare that the two Map objects have the same keys and values for each key and have no extra keys.
没有“标准”或“内置”的方式来做到这一点。从概念上讲,您只需比较两个 Map 对象对于每个键具有相同的键和值,并且没有额外的键。
To be as efficient about the comparison as possible, you can do the following optimizations:
为了尽可能高效地进行比较,您可以进行以下优化:
- First check the
.size
property on both maps. If the two maps don't have the same number of keys, then you know right away, they can't be identical. - Furthermore, guaranteeing that they have the same number of keys allows you to just iterate one of the maps and compare its values to the other.
- Use the
for (var [key, val] of map1)
iterator syntax for iterating the keys so you don't have to build or sort an array of keys yourself (should be both faster and more memory efficient). - Then, lastly, if you make sure that the comparison returns immediately as soon as a mismatch is found, then it will shorten the execution time when they are not the same.
- 首先检查
.size
两个地图上的属性。如果两个映射没有相同数量的键,那么您马上就会知道,它们不能相同。 - 此外,保证它们具有相同数量的键允许您只迭代其中一个映射并将其值与另一个进行比较。
- 使用
for (var [key, val] of map1)
迭代器语法来迭代键,这样您就不必自己构建或排序键数组(应该更快,内存效率更高)。 - 然后,最后,如果您确保一旦发现不匹配就立即返回比较,那么当它们不相同时,它将缩短执行时间。
Then, since undefined
is a legal value in a Map, but it's also what .get()
returns if the key is not found, we have to watch out for that by doing an extra .has()
if the value we're comparing is undefined
.
然后,由于undefined
是 Map 中的合法值,但.get()
如果未找到键,则它也是返回的值,因此我们必须通过执行额外操作来注意这一点,.has()
如果我们正在比较的值是undefined
。
Since both keys and values with a Map object can be objects themselves, this gets much trickier if you want a deep property comparison of objects to determine equality rather than just the more simple ===
that Javascript uses by default to test for the same object. Or, if you're only interested in objects that have primitives for keys and values, then this complexity can be avoided.
由于 Map 对象的键和值本身都可以是对象,因此如果您想要对对象进行深入的属性比较以确定相等性,而不仅仅是===
Javascript 默认使用的更简单的方法来测试同一对象,这将变得更加棘手。或者,如果您只对具有键和值的基元的对象感兴趣,则可以避免这种复杂性。
For a function that tests only strict value equality (checks objects to see if they are the same physical object, not a deep property comparison), you can do what is shown below. This uses ES6 syntax for efficient iteration of the map objects and attempts to improve performance when they do not match by short circuiting and returning false
as soon as a mismatch is found.
对于仅测试严格值相等性的函数(检查对象以查看它们是否是相同的物理对象,而不是深度属性比较),您可以执行如下所示的操作。这使用 ES6 语法来高效迭代地图对象,并在它们不匹配时尝试通过短路并false
在发现不匹配时立即返回来提高性能。
"use strict";
function compareMaps(map1, map2) {
var testVal;
if (map1.size !== map2.size) {
return false;
}
for (var [key, val] of map1) {
testVal = map2.get(key);
// in cases of an undefined value, make sure the key
// actually exists on the object so there are no false positives
if (testVal !== val || (testVal === undefined && !map2.has(key))) {
return false;
}
}
return true;
}
// construct two maps that are initially identical
var o = {"k" : 2}
var m1 = new Map();
m1.set("obj", o);
m1.set("str0", undefined);
m1.set("str1", 1);
m1.set("str2", 2);
m1.set("str3", 3);
var m2 = new Map();
m2.set("str0", undefined);
m2.set("obj", o);
m2.set("str1", 1);
m2.set("str2", 2);
m2.set("str3", 3);
log(compareMaps(m1, m2));
// add an undefined key to m1 and a corresponding other key to m2
// this will pass the .size test and even pass the equality test, but not pass the
// special test for undefined values
m1.set("str-undefined", undefined);
m2.set("str4", 4);
log(compareMaps(m1, m2));
// remove one key from m1 so m2 has an extra key
m1.delete("str-undefined");
log(compareMaps(m1, m2));
// add that same extra key to m1, but give it a different value
m1.set("str4", 5);
log(compareMaps(m1, m2));
function log(args) {
var str = "";
for (var i = 0; i < arguments.length; i++) {
if (typeof arguments[i] === "object") {
str += JSON.stringify(arguments[i]);
} else {
str += arguments[i];
}
}
var div = document.createElement("div");
div.innerHTML = str;
var target = log.id ? document.getElementById(log.id) : document.body;
target.appendChild(div);
}
If you wanted to do deep object comparison rather than just comparing to see if they are physically the same object, where values could be objects or arrays, then life gets a lot more complicated.
如果您想进行深入的对象比较,而不仅仅是比较它们在物理上是否是同一个对象,其中值可以是对象或数组,那么生活就会变得更加复杂。
To do that, you need a deep object comparison method that takes into account all of the following:
为此,您需要一种深度对象比较方法,该方法考虑了以下所有内容:
- Recursive comparison for nested objects
- Protection against circular references (which can cause an infinite loop)
- Knowledge of how to compare some types of built-in objects such as a
Date
.
- 嵌套对象的递归比较
- 防止循环引用(可能导致无限循环)
- 了解如何比较某些类型的内置对象,例如
Date
.
Since a lot has been written elsewhere about how to do a deep object comparison (including a number of highly voted answers here on StackOverflow), I will assume that is not the main part of your question.
由于其他地方已经写了很多关于如何进行深度对象比较的文章(包括 StackOverflow 上的一些高票答案),我认为这不是您问题的主要部分。
回答by Mrchief
If your Map
has onlystring keys, then you can use this approach to compare them:
如果您Map
有唯一的字符串键,那么您可以使用此方法对它们进行比较:
const mapToObj = (map) => {
let obj = Object.create(null)
for (let [k,v] of map) {
// We don't escape the key '__proto__'
// which can cause problems on older engines
obj[k] = v
}
return obj
}
assert.deepEqual(mapToObj(myMap), myExpectedObj)
Note:deepEqual
is part of many testing suites and if not, you can use lodash/underscore equivalents. Any function that does a deep comparison will do.
注意:deepEqual
是许多测试套件的一部分,如果不是,您可以使用 lodash/underscore 等效项。任何进行深度比较的函数都可以。
mapToObj
function courtesy of http://exploringjs.com/es6/ch_maps-sets.html
回答by quantdaddy
Note that the solution proposed by @jfriend00 does not work in typescript ES2016. See this for the right answer: iteration over a typescript map failing
请注意,@jfriend00 提出的解决方案在 typescript ES2016 中不起作用。请参阅此以获取正确答案:iteration over a typescript map failed