How can I check if two Map objects are equal?

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.

To be as efficient about the comparison as possible, you can do the following optimizations:

  1. 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.
  2. 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.
  3. 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).
  4. 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.

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.

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.

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.

"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);
}

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:

  1. Recursive comparison for nested objects
  2. Protection against circular references (which can cause an infinite loop)
  3. Knowledge of how to compare some types of built-in objects such as a 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.

Leave a Comment