การทำซ้ำบนแผนที่ typescript


136

ฉันกำลังพยายามทำซ้ำบนแผนที่ typescript แต่ฉันได้รับข้อผิดพลาดอยู่เรื่อย ๆ และยังไม่พบวิธีแก้ปัญหาใด ๆ สำหรับปัญหาเล็กน้อยดังกล่าว

รหัสของฉันคือ:

myMap : Map<string, boolean>;
for(let key of myMap.keys()) {
   console.log(key);
}

และฉันได้รับข้อผิดพลาด:

พิมพ์ 'IterableIteratorShim <[string, boolean]>' ไม่ใช่ประเภทอาร์เรย์หรือประเภทสตริง

การติดตามกองเต็ม:

 Error: Typescript found the following errors:
  /home/project/tmp/broccoli_type_script_compiler-input_base_path-q4GtzHgb.tmp/0/src/app/project/project-data.service.ts (21, 20): Type 'IterableIteratorShim<[string, boolean]>' is not an array type or a string type.
    at BroccoliTypeScriptCompiler._doIncrementalBuild (/home/project/node_modules/angular-cli/lib/broccoli/broccoli-typescript.js:115:19)
    at BroccoliTypeScriptCompiler.build (/home/project/node_modules/angular-cli/lib/broccoli/broccoli-typescript.js:43:10)
    at /home/project/node_modules/broccoli-caching-writer/index.js:152:21
    at lib$rsvp$$internal$$tryCatch (/home/project/node_modules/rsvp/dist/rsvp.js:1036:16)
    at lib$rsvp$$internal$$invokeCallback (/home/project/node_modules/rsvp/dist/rsvp.js:1048:17)
    at lib$rsvp$$internal$$publish (/home/project/node_modules/rsvp/dist/rsvp.js:1019:11)
    at lib$rsvp$asap$$flush (/home/project/node_modules/rsvp/dist/rsvp.js:1198:9)
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickCallback (internal/process/next_tick.js:98:9)

ฉันใช้ angular-cli beta5 และ typescript 1.8.10 และเป้าหมายของฉันคือ es5 มีใครมีปัญหานี้บ้าง?


4
ดูคำตอบนี้ได้จาก github github.com/Microsoft/TypeScript/issues/…
yurzui

คำตอบ:


214

คุณสามารถใช้Map.prototype.forEach((value, key, map) => void, thisArg?) : voidแทนได้

ใช้แบบนี้:

myMap.forEach((value: boolean, key: string) => {
    console.log(key, value);
});

16
เพิ่งวิ่งเข้าไปในนี้ ดูเหมือนว่า TypeScript จะไม่เคารพข้อมูลจำเพาะสำหรับการวนซ้ำแผนที่อย่างน้อยก็เป็นไปตามMDNซึ่งระบุ for-of loop .forEachเป็นสิ่งที่ดีที่สุดเนื่องจากคุณไม่สามารถทำลายมันได้ AFAIK
Samjones

14
ไม่รู้ทำไมค่าของมันจึงสำคัญ ดูเหมือนถอยหลัง
Paul Rooney

@PaulRooney มันเป็นแบบนั้นที่อาจจะเข้ากันArray.prototype.mapได้
Ahmed Fasih

1
จะหยุดกระบวนการทำซ้ำนี้ได้อย่างไรหากเราพบสิ่งที่ต้องการ
JavaRunner

37

ES6

for (let [key, value] of map) {
    console.log(key, value);
}

ES5

for (let entry of Array.from(map.entries())) {
    let key = entry[0];
    let value = entry[1];
}

1
เวอร์ชัน es6 ที่ระบุข้างต้นไม่ได้รวบรวมในโหมดเข้มงวด
Stephane

ขอบคุณครับ.
Kitanga Nday

36

เพียงแค่ใช้Array.from()วิธีการแปลงเป็นArray:

myMap : Map<string, boolean>;
for(let key of Array.from( myMap.keys()) ) {
   console.log(key);
}

5
การแปลงแผนที่เป็นการดำเนินการที่มีประสิทธิภาพมากและไม่ใช่วิธีที่ถูกต้องในการแก้ปัญหาซึ่งโดยพื้นฐานแล้วเป็นเพียงคอมไพเลอร์ที่ซ่อนส่วนหลักของภาษา เพียงแค่แคสต์<any>แผนที่เพื่อทำซ้ำด้วย for-of
Kilves

1
ระวัง: ฉันคิดว่าคำแนะนำของ @Kilves ข้างต้นในการส่งแผนที่เป็น "ใดก็ได้" เป็นวิธีแก้ปัญหาที่ดี เมื่อฉันทำมันโค้ดจะคอมไพล์และทำงานโดยไม่มีการร้องเรียน แต่แผนที่ไม่ได้รับการทำซ้ำ - เนื้อหาของลูปไม่เคยดำเนินการ Array.from()กลยุทธ์ที่นำเสนอที่นี่ได้ทำงานสำหรับฉัน
mactyr

ฉันก็ลองทำเช่นกันมันก็ไม่ได้ผลสำหรับฉันเช่นกันซึ่งแม้แต่คนที่มึนงงก็คิดว่ามันเป็นส่วนหนึ่งของ ES6 และควรจะ "ใช้ได้" ในเบราว์เซอร์ส่วนใหญ่ แต่ฉันเดาว่าโอเวอร์ลอร์ดเชิงมุมของเราใช้จัมโบ้ mumbo มายากลใน zone.js เพื่อให้มันใช้ไม่ได้เพราะพวกมันเกลียด ES6 ถอนหายใจ
Kilves

28

การใช้Array.from , Array.prototype.forEach ()และฟังก์ชันลูกศร :

ย้ำคีย์ :

Array.from(myMap.keys()).forEach(key => console.log(key));

วนซ้ำค่า :

Array.from(myMap.values()).forEach(value => console.log(value));

วนซ้ำรายการ :

Array.from(myMap.entries()).forEach(entry => console.log('Key: ' + entry[0] + ' Value: ' + entry[1]));

2
ไม่แน่ใจว่าทำไมฉันถึงมีแผนที่เช่น Map <String, CustomeClass> วิธีการข้างต้นไม่ได้ผลยกเว้น Array.from (myMap.values ​​()) forEach (value => console.log (value));.
Rajashree Gr

28

สิ่งนี้ได้ผลสำหรับฉัน เวอร์ชัน TypeScript: 2.8.3.2

for (const [key, value] of Object.entries(myMap)) { 
    console.log(key, value);
}

7
ฉันทำให้สิ่งนี้ทำงานได้โดยเปลี่ยน Object.entries (myMap) เป็นแค่ myMap.entries () ฉันชอบคำตอบนี้เพราะหลีกเลี่ยงข้อผิดพลาดในการจัดการข้อผิดพลาดของ. สำหรับการโทรแต่ละครั้ง
ล้อมรอบ

2
ที่น่าสังเกตว่าหากคุณtargetเข้าtsconfigสิ่งes5นี้จะทำให้เกิดข้อผิดพลาด แต่es6ทำงานได้อย่างถูกต้อง คุณสามารถทำได้for (const [key, value] of myMap)เมื่อกำหนดเป้าหมายes6
Benjamin Vogler

16

ตามบันทึกประจำรุ่น TypeScript 2.3 เรื่อง "ใหม่--downlevelIteration" :

for..of statements, Array Destructuring, และ Spread องค์ประกอบใน Array, Call และนิพจน์ใหม่รองรับ Symbol.iterator ใน ES5 / E3 หากมีเมื่อใช้ --downlevelIteration

ไม่ได้เปิดใช้งานโดยค่าเริ่มต้น! เพิ่ม"downlevelIteration": trueลงในแฟล็กของคุณtsconfig.jsonหรือส่งผ่าน--downlevelIterationไปที่tscเพื่อรับการสนับสนุนตัววนซ้ำแบบเต็ม

ด้วยสิ่งนี้คุณสามารถเขียนfor (let keyval of myMap) {...}และkeyvalประเภทของจะถูกอนุมานโดยอัตโนมัติ


เหตุใดสิ่งนี้จึงถูกปิดโดยค่าเริ่มต้น ตาม typescript ส่วนร่วม@aluanhaddad ,

เป็นทางเลือกเนื่องจากมีผลกระทบอย่างมากต่อขนาดของโค้ดที่สร้างขึ้นและอาจมีผลต่อประสิทธิภาพสำหรับการใช้งานซ้ำทั้งหมด (รวมถึงอาร์เรย์)

หากคุณสามารถกำหนดเป้าหมาย ES2015 ( "target": "es2015"ในtsconfig.jsonหรือtsc --target ES2015) หรือใหม่กว่าได้การเปิดใช้งานdownlevelIterationไม่ใช่เรื่องง่าย แต่หากคุณกำหนดเป้าหมาย ES5 / ES3 คุณอาจเปรียบเทียบเพื่อให้แน่ใจว่าการสนับสนุนตัววนซ้ำจะไม่ส่งผลกระทบต่อประสิทธิภาพ (ถ้าเป็นเช่นนั้นคุณอาจจะดีกว่า ปิดด้วยArray.fromการแปลงหรือforEachหรือวิธีแก้ปัญหาอื่น ๆ )


ตกลงหรือเป็นอันตรายเมื่อเปิดใช้งานเมื่อใช้ Angular?
Simon_Weaver

9

สิ่งนี้ได้ผลสำหรับฉัน

Object.keys(myMap).map( key => {
    console.log("key: " + key);
    console.log("value: " + myMap[key]);
});

2
ด้วยสิ่งนี้คีย์จะเป็นสตริงเสมอ
Ixx

8

ฉันใช้ TS และโหนดล่าสุด (v2.6 และ v8.9 ตามลำดับ) และฉันสามารถทำได้:

let myMap = new Map<string, boolean>();
myMap.set("a", true);
for (let [k, v] of myMap) {
    console.log(k + "=" + v);
}

คุณสามารถยืนยันได้ว่าครั้งแรกที่คุณจะต้องตั้งค่า"downlevelIteration": trueในของคุณtsconfig.json?
Ahmed Fasih

3
ฉันไม่ได้downlevelIteratonตั้งเป้าหมายไว้es2017อย่างไรก็ตาม
lazieburd

ฉันไม่สามารถทำสิ่งนี้สำหรับองค์ประกอบแผนที่ <string, CustomClass []> ได้หรือไม่ คอมไพเลอร์บอกว่าไม่ใช่อาร์เรย์ประเภทหรือสตริง
Rajashree Gr

สิ่งนี้ใช้ไม่ได้สำหรับฉันใน 2.8 - ฉันได้รับType 'Map<K, V>' is not an array type or a string type.
Simon_Weaver

3

คุณยังสามารถใช้วิธีการแม็พอาร์เรย์กับ Map.entries () ซ้ำได้:

[...myMap.entries()].map(
     ([key, value]: [string, number]) => console.log(key, value)
);

ตามที่ระบุไว้ในคำตอบอื่น ๆ คุณอาจต้องเปิดใช้งานการวนซ้ำระดับลงใน tsconfig.json ของคุณ (ภายใต้ตัวเลือกคอมไพเลอร์):

  "downlevelIteration": true,

คุณลักษณะนี้เปิดตัวใน TypeScript 2.3 ปัญหาเกิดขึ้นกับ TypeScript 1.8.10
mwe

หากคุณไม่สามารถใช้ "downlevelIteration" คุณสามารถใช้:const projected = Array.from(myMap).map(...);
Efrain

1

คำอธิบายง่ายๆสำหรับใช้ในเอกสาร HTML

หากคุณมีแผนที่ประเภท (คีย์อาร์เรย์) คุณจะเริ่มต้นอาร์เรย์ด้วยวิธีนี้:

public cityShop: Map<string, Shop[]> = new Map();

และในการวนซ้ำคุณสร้างอาร์เรย์จากค่าคีย์

เพียงใช้เป็นอาร์เรย์ใน:

keys = Array.from(this.cityShop.keys());

จากนั้นใน HTML คุณสามารถใช้:

*ngFor="let key of keys"

ภายในลูปนี้คุณจะได้รับค่าอาร์เรย์ด้วย:

this.cityShop.get(key)

ทำ!



-1

หากคุณไม่ชอบฟังก์ชั่นที่ซ้อนกันจริงๆคุณสามารถทำซ้ำบนปุ่มต่างๆ:

myMap : Map<string, boolean>;
for(let key of myMap) {
   if (myMap.hasOwnProperty(key)) {
       console.log(JSON.stringify({key: key, value: myMap[key]}));
   }
}

หมายเหตุคุณต้องกรองการทำซ้ำที่ไม่ใช่คีย์ด้วยhasOwnPropertyถ้าคุณไม่ทำเช่นนี้คุณจะได้รับคำเตือนหรือข้อผิดพลาด


จะวนซ้ำบนแผนที่ใน html ได้อย่างไร? ดูเหมือนจะไม่ได้ผลเลย <div ng-repeat = "(คีย์ค่า) ใน model.myMap"> {{key}} </div>
Shinya Koizumi

@ powerfade917 มันใช้ไม่ได้มันใช้ได้กับอาร์เรย์เท่านั้นเพราะเชิงมุมเป็นกองขยะ แต่ขอให้เป็นคำถามใหม่แล้วคุณจะได้เรียนรู้ว่าเชิงมุมไม่ใช่กองขยะ แต่คุณต้องแปลงเป็นอาร์เรย์ โปรดทราบว่าคุณไม่ได้อยู่ในอันดับต้น ๆ ของการเขียนโปรแกรมเนื่องจากดูเหมือนว่าคุณจะไม่สามารถแยกความแตกต่างระหว่างเชิงมุมและแบบพิมพ์ได้
peterh - คืนสถานะ Monica
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.