I'm using the function below to compare two maps. What's interesting is that the code inside for loop is never executed. So, console.log(key,val)
code is never executed. Of course I made sure that the maps I'm comparing are not empty and are of same size to force execution of the code inside the for loop. Am I making a really silly mistake or am missing a deep concept?
private compareMaps(map1, map2) {
var testVal;
if (!(map1 && map2)) {
return false;
}
if (map1.size !== map2.size) {
return false;
}
for (var [key, val] of map1) {
testVal = map2.get(key);
console.log(key, val);
if (testVal !== val || (testVal === undefined && !map2.has(key))) {
return false;
}
}
return true;
}
What's interesting is that the code inside for loop is never executed. Am I making a really silly mistake or am missing a deep concept?
You're missing the fact that...
for...of
does not work on Map
in TypeScript prior to ES6When it targets ECMAScript prior to ES6, the TypeScript compiler transpiles the for...of
statement into a for
loop.
This code:
for (var [key, val] of map) {
console.log(key);
}
Becomes this code:
for (var _i = 0, map_1 = map; _i < map_1.length; _i++) {
var _a = map_1[_i], key = _a[0], val = _a[1];
console.log(key);
}
What to do?
Option 1: When we must target ECMAScript prior to ES6, the forEach
function can be a suitable alternative to the for...of
loop. Beware though that forEach
has subtle differences from for...of
(e.g. exiting early, async/await).
map.forEach((val, key) => {
console.log(key + ":" + val);
});
Option 2: When we must target ECMAScript prior to ES6, and we must have the exact behavior of for...of
, the answer by John Weisz makes sense: convert the Map
to an Array
and iterate the Array
with for...of
.
Option 3: When we can target ECMAScript ES6 or later, use the for...of
loop directly on the Map
.
If the requirement is Map equality, consider the every
function. That takes care of the need to break
in the iteration, because every
immediately returns when it finds the first false
.
If order matters to the comparison, use every
like this:
function areEqual<K,V>(map1: Map<K,V>, map2: Map<K,V>) {
if(!map1 || !map2) return false;
const array1 = Array.from(map1.entries());
const array2 = Array.from(map2.entries());
return array1.every(([k1, v1], index) => {
const [k2, v2] = array2[index];
return k1 === k2 && v1 === v2;
});
}
If order does not matter, then we want set equality; use every
like this:
function areSetEqual<K, V>(map1: Map<K, V>, map2: Map<K, V>) {
if(!map1 || !map2) return false;
const array1 = Array.from(map1.entries());
const array2 = Array.from(map2.entries());
return array1.length === array2.length &&
array1.every(([k1, v1]) => map2.get(k1) === v1);
}
Here is a demo of the functions in action:
const map1 = new Map([["key1", "val1"], ["key2", "val2"]]);
const map2 = new Map([["key1", "val1"], ["key2", "val2"]]);
const map3 = new Map([["key2", "val2"], ["key1", "val1"]]);
console.log(areEqual(map1, map2)); // true
console.log(areEqual(map1, map3)); // false
console.log(areSetEqual(map1, map2)); // true
console.log(areSetEqual(map1, map3)); // true
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With