对打字稿地图的迭代失败 [英] iteration over a typescript map failing
问题描述
我正在使用下面的函数比较两张地图。有趣的是for循环中的代码永远不会被执行。因此, console.log(key,val)
代码永远不会执行。当然,我确保我正在比较的地图不是空的,并且大小相同,以强制执行for循环中的代码。我犯了一个非常愚蠢的错误或错过了一个深刻的概念吗?
private compareMaps(map1,map2){
var testVal;
if(!(map1&& map2)){
return false;
}
if(map1.size!== map2.size){
return false;
}
for(var [key,val] map1){
testVal = map2.get(key);
console.log(key,val);
if(testVal!== val ||(testVal === undefined&&!map2.has(key))){
return false;
}
}
返回true;
}
有趣的是for循环中的代码永远不会被执行。我犯了一个非常愚蠢的错误或错过了一个深刻的概念吗?
你错过了......
for ... of
在TypeScript中的 Map
上不起作用在ES6之前
当它在ES6之前定位ECMAScript时,TypeScript编译器为语句的...转换进入
for
循环。
此代码:
for(var [key,val]地图){
console.log(key);
}
成为此代码:
($ _ $ = 0,map_1 = map; _i< map_1.length; _i ++){
var _a = map_1 [_i],key = _a [0 ],val = _a [1];
console.log(key);
}
怎么办?
选项1 :当我们必须在ES6之前定位ECMAScript时, forEach
函数可以替代 for ... of
循环。请注意, forEach
对于的有微妙的差异(例如,提前退出,async / await)。
map.forEach((val,key)=> {
console.log(key +:+ val);
});
选项2 :当我们必须在ES6之前定位ECMAScript时,我们必须具有的确切行为
, John Weisz的答案有意义:将 Map
转换为数组
并迭代数组
的
。
选项3 :当我们可以定位 ECMAScript ES6或更高版本时,请使用 for ... of
地图
上循环。
旁白:地图平等
如果要求是地图平等,请考虑 每个
函数。这需要在迭代中 break
的需要,因为每个
在找到第一个<$ c时立即返回$ c> false 。
如果订单比较重要,请使用每
像这样:
function areEqual< K,V>(map1:Map< K,V>, map2:Map< K,V>){
if(!map1 ||!map2)返回false;
const array1 = Array.from(map1.entries());
const array2 = Array.from(map2.entries());
返回array1.every(([k1,v1],index)=> {
const [k2,v2] = array2 [index];
返回k1 === k2& & v1 === v2;
});
}
如果订单无关紧要,那么我们想要集平等;使用每个
,如下所示:
function areSetEqual< K,V>( map1:Map< K,V>,map2:Map< K,V>){
if(!map1 ||!map2)返回false;
const array1 = Array.from(map1.entries());
const array2 = Array.from(map2.entries());
返回array1.length === array2.length&&
array1.every(([k1,v1])=> map2.get(k1)=== v1);
}
以下是有效功能的演示:
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
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 ES6
When 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
.
Aside: Map Equality
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
这篇关于对打字稿地图的迭代失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!