Iterasi di atas Peta Ketikan


135

Saya mencoba untuk mengulangi peta ketikan tetapi saya terus mendapatkan kesalahan dan saya belum bisa menemukan solusi untuk masalah sepele seperti itu.

Kode saya adalah:

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

Dan saya mendapatkan Error:

Jenis 'IterableIteratorShim <[string, boolean]>' bukan jenis larik atau jenis string.

Jejak Tumpukan Penuh:

 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)

Saya menggunakan angular-cli beta5 dan typescript 1.8.10 dan target saya adalah es5. Adakah yang punya masalah ini?


4
Lihat jawaban ini dari github github.com/Microsoft/TypeScript/issues/…
yurzui

Jawaban:


212

Anda bisa menggunakan Map.prototype.forEach((value, key, map) => void, thisArg?) : voidsebagai gantinya

Gunakan seperti ini:

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

15
Baru saja mengalami ini. Sepertinya TypeScript tidak menghormati spesifikasi untuk iterasi peta, setidaknya menurut MDN yang menetapkan perulangan for-of. .forEachkurang optimal, karena Anda tidak dapat memecahkannya, AFAIK
Samjones

14
tidak tahu mengapa nilainya lalu kuncinya. Sepertinya mundur.
Paul Rooney

@PaulRooney mungkin seperti itu untuk selaras Array.prototype.map.
Ahmed Fasih

1
Bagaimana cara menghentikan proses iterasi ini jika kami menemukan apa yang kami butuhkan?
JavaRunner

36

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
Versi es6 yang diberikan di atas tidak dikompilasi dalam mode ketat.
Stephane

Terima kasih tuan yang baik.
Kitanga Nday

36

Cukup gunakan Array.from()metode untuk mengubahnya menjadi fileArray :

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

5
Mengonversi peta adalah operasi yang sangat haus kinerja dan bukan cara yang tepat untuk memecahkan masalah yang pada dasarnya hanya penyusun yang menyembunyikan bagian inti dari bahasa tersebut. Cukup- <any>siarkan peta untuk mengulanginya dengan for-of.
Kilves

1
Waspadalah: Saya pikir saran @Kilves di atas untuk mengubah Peta menjadi "any" adalah solusi yang bagus. Ketika saya melakukannya, kode dikompilasi dan dijalankan tanpa keluhan, tetapi Peta sebenarnya tidak diiterasi - konten loop tidak pernah dieksekusi. The Array.from()strategi yang diusulkan di sini melakukan pekerjaan untuk saya.
mactyr

Saya mencobanya juga, itu juga tidak berhasil untuk saya, yang bahkan lebih bodoh mengingat ini adalah bagian dari ES6 dan seharusnya "berfungsi" di sebagian besar browser. Tapi saya kira tuan sudut kami menggunakan beberapa omong kosong ajaib di zone.js untuk membuatnya tidak berfungsi, karena mereka membenci ES6. Mendesah.
Kilves

28

Menggunakan fungsi Array.from , Array.prototype.forEach () , dan panah :

Iterasi di atas kunci :

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

Iterasi nilai :

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

Iterasi entri :

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

2
Tidak yakin mengapa, saya memiliki peta seperti Map <String, CustomeClass>. tidak ada metode di atas yang berfungsi kecuali Array.from (myMap.values ​​()). forEach (value => console.log (value)) ;.
Rajashree Gr

27

Ini berhasil untuk saya. Versi TypeScript: 2.8.3

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

7
Saya mendapatkan ini untuk bekerja dengan mengubah Object.entries (myMap) menjadi hanya myMap.entries (). Saya menyukai jawaban ini karena menghindari kesalahan penanganan kesalahan panggilan .forEach.
berakhir

2
Perlu dicatat bahwa jika Anda targetdi tsconfigadalah es5ini melempar kesalahan, tapi dengan es6karya-karya dengan benar. Anda juga dapat melakukannya for (const [key, value] of myMap)saat menargetkanes6
Benjamin Vogler

16

Sesuai catatan rilis TypeScript 2.3 tentang "Baru --downlevelIteration" :

for..of statements, Array Destructuring, dan elemen Spread di Array, Call, dan ekspresi baru mendukung Symbol.iterator di ES5 / E3 jika tersedia saat menggunakan --downlevelIteration

Ini tidak diaktifkan secara default! Tambahkan "downlevelIteration": trueke Anda tsconfig.json, atau berikan --downlevelIterationbendera ke tsc, untuk mendapatkan dukungan iterator penuh.

Dengan ini, Anda dapat menulis for (let keyval of myMap) {...}dan keyvaltipe akan disimpulkan secara otomatis.


Mengapa ini dimatikan secara default? Menurut kontributor TypeScript @aluanhaddad ,

Ini opsional karena memiliki dampak yang sangat signifikan pada ukuran kode yang dihasilkan, dan berpotensi pada kinerja, untuk semua penggunaan iterable (termasuk array).

Jika Anda dapat menargetkan ES2015 ( "target": "es2015"dalam tsconfig.jsonatau tsc --target ES2015) atau lebih baru, mengaktifkannya downlevelIterationtidak perlu dipikirkan lagi, tetapi jika Anda menargetkan ES5 / ES3, Anda dapat melakukan tolok ukur untuk memastikan dukungan iterator tidak memengaruhi kinerja (jika ya, Anda mungkin lebih baik off dengan Array.fromkonversi atau forEachatau solusi lain).


apakah ini baik atau berbahaya untuk mengaktifkan ini saat menggunakan Angular?
Simon_Weaver

9

Ini berhasil untuk saya.

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

2
Dengan ini, kuncinya akan selalu menjadi string
Ixx

8

Saya menggunakan TS dan node terbaru (masing-masing v2.6 dan v8.9) dan saya dapat melakukan:

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

Dapatkah Anda mengkonfirmasi bahwa Anda pertama kali harus set "downlevelIteration": truedi Anda tsconfig.json?
Ahmed Fasih

3
Saya belum downlevelIteratonmenetapkan, es2017namun target saya .
lazieburd

Tidak dapatkah saya melakukan ini untuk elemen Map <string, CustomClass []>? compiler mengatakan itu bukan array tipe atau tipe string.
Rajashree Gr

ini tidak bekerja untuk saya di 2.8 - Saya mengertiType 'Map<K, V>' is not an array type or a string type.
Simon_Weaver

3

Anda juga bisa menerapkan metode peta larik ke iterable Map.entries ():

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

Juga, seperti disebutkan dalam jawaban lain, Anda mungkin harus mengaktifkan iterasi tingkat bawah di tsconfig.json Anda (di bawah opsi kompiler):

  "downlevelIteration": true,

Fitur ini diperkenalkan di TypeScript 2.3. Masalah terjadi dengan TypeScript 1.8.10
mwe

Jika Anda tidak dapat menggunakan "downlevelIteration", Anda dapat menggunakan:const projected = Array.from(myMap).map(...);
Efrain

1

Hanya penjelasan sederhana untuk menggunakannya dalam dokumen HTML.

Jika Anda memiliki Map of types (key, array) maka Anda menginisialisasi array dengan cara ini:

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

Dan untuk mengulanginya, Anda membuat array dari nilai kunci.

Gunakan saja sebagai array seperti pada:

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

Kemudian, dalam HTML, Anda dapat menggunakan:

*ngFor="let key of keys"

Di dalam loop ini, Anda baru saja mendapatkan nilai array dengan:

this.cityShop.get(key)

Selesai!


1

Pada Typecript 3.5 dan Angular 8 LTS, diharuskan untuk menggunakan tipe sebagai berikut:

for (let [k, v] of Object.entries(someMap)) {
    console.log(k, v)
}

-1

Jika Anda tidak terlalu menyukai fungsi bersarang, Anda juga dapat melakukan iterasi pada tombol:

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

Catatan, Anda harus memfilter iterasi non-kunci dengan hasOwnProperty, jika Anda tidak melakukan ini, Anda akan mendapatkan peringatan atau kesalahan.


bagaimana cara mengulang peta di html? sepertinya tidak berhasil sama sekali. <div ng-repeat = "(key, value) di model.myMap"> {{key}}. </div>
Shinya Koizumi

@ powerfade917 Ini tidak bekerja, ini hanya bekerja untuk array karena sudut adalah tumpukan sampah. Tapi tanyakan ini sebagai pertanyaan baru dan Anda akan belajar, bahwa angular bukanlah tumpukan sampah, tapi Anda harus mengubahnya menjadi sebuah array. Perhatikan, Anda juga bukan yang teratas dari pemrograman, karena Anda tampaknya tidak mampu membedakan antara angular dan skrip.
peterh - Pulihkan Monica
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.