如何检查两个ES2015 Map对象是否具有相同的(键,值)
对集合?
我们假设所有键和值都是原始数据类型。
解决此问题的一种方法是使用map.entries()
,从中创建数组,然后按键对该数组进行排序。并且针对另一个Map也执行相同的操作。然后循环遍历这两个数组以比较它们。但是这种方法非常麻烦,还由于排序(性能低效)和创建数组(内存低效)而非常低效。
是否有更好的方法呢?
如何检查两个ES2015 Map对象是否具有相同的(键,值)
对集合?
我们假设所有键和值都是原始数据类型。
解决此问题的一种方法是使用map.entries()
,从中创建数组,然后按键对该数组进行排序。并且针对另一个Map也执行相同的操作。然后循环遍历这两个数组以比较它们。但是这种方法非常麻烦,还由于排序(性能低效)和创建数组(内存低效)而非常低效。
是否有更好的方法呢?
"use strict";
function compareMaps(map1, map2) {
let testVal;
if (map1.size !== map2.size) {
return false;
}
for (let [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
const o = {"k" : 2}
const m1 = new Map();
m1.set("obj", o);
m1.set("str0", undefined);
m1.set("str1", 1);
m1.set("str2", 2);
m1.set("str3", 3);
const 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) {
let str = "";
for (let i = 0; i < arguments.length; i++) {
if (typeof arguments[i] === "object") {
str += JSON.stringify(arguments[i]);
} else {
str += arguments[i];
}
}
const div = document.createElement("div");
div.innerHTML = str;
const target = log.id ? document.getElementById(log.id) : document.body;
target.appendChild(div);
}
如果你想进行深度对象比较而不仅仅是比较它们是否为同一物理对象,其中值可以是对象或数组,那么情况会变得更加复杂。
为此,您需要一个深度对象比较方法,该方法考虑了以下所有内容:
Date
。由于关于如何进行深度对象比较已经在其他地方写了很多内容(包括在StackOverflow上有很多高票答案),我将假设这不是你问题的主要部分。
.size
比较,所以我需要第二个循环来处理m2
中的额外键,但现在我有了.size
比较,我认为你是对的。我会删除第二个循环。 - jfriend00undefined
,那么第一个版本的代码将把它与缺失的键匹配,因为当键缺失时 .get()
返回的就是这个。 - jfriend00undefined
值问题添加了另一个测试用例。 - jfriend00const mapsAreEqual = (m1, m2) => m1.size === m2.size && Array.from(m1.keys()).every((key) => m1.get(key) === m2.get(key));
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)
注意: deepEqual
是许多测试套件的一部分,如果没有,您可以使用lodash/underscore等同函数。任何进行深度比较的函数都可以。
mapToObj
函数由http://exploringjs.com/es6/ch_maps-sets.html提供。
/**
* The utility function that returns an intersection of two Sets
*
* @returns an array of items in common
*/
function intersection<T>(a: Set<T>, b: Set<T>): T[] {
return Array.from(a).filter(x => b.has(x));
}
/**
* Compares two Maps
*
* @param compare is an optional function for values comparison
* @returns `true` if they are equal, and `false` otherwise
*/
function compareMaps<T>(a: Map<string, T>, b: Map<string, T>, compare?: (aValue: T, bValue: T) => boolean): boolean {
const common = intersection(new Set(a.keys()), new Set(b.keys()));
return a.size === b.size &&
common.length === a.size &&
common.every(key =>
compare?.(a.get(key) as T, b.get(key) as T) ?? a.get(key) === b.get(key));
}
Map<string, object>
不起作用,因为以下行不会正确评估两个对象:
if (testVal !== val || (testVal === undefined && !map2.has(key))) {
Map<string, object>
。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 (JSON.stringify(testVal) !== JSON.stringify(val) || (testVal === undefined && !map2.has(key))) {
return false;
}
}
return true;
}
JSON.stringify(obj)
不是比较对象的规范方法,因为不能保证对象上的属性在JSON中的顺序相同。实际上,对对象进行深度比较需要更多的操作。 - jfriend00
Date
)等问题。如果仅涉及字符串、数字或布尔值,则不是那么困难。目前您的问题并未说明您只是尝试解决简单情况还是需要嵌套对象的复杂情况。 - jfriend00