Lặp lại trên Bản đồ bản in


134

Tôi đang cố gắng lặp lại trên bản đồ bản thảo nhưng tôi vẫn gặp lỗi và tôi không thể tìm thấy bất kỳ giải pháp nào cho một vấn đề tầm thường như vậy.

Mã của tôi là:

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

Và tôi nhận được Lỗi:

Loại 'IterableIteratorShim <[chuỗi, boolean]>' không phải là kiểu mảng hoặc kiểu chuỗi.

Trace Stack đầy đủ:

 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)

Tôi đang sử dụng angular-cli beta5 và bản đánh máy 1.8.10 và mục tiêu của tôi là es5. Có ai có vấn đề này?


4
Xem câu trả lời này từ github github.com/Microsoft/TypeScript/issues/
Kẻ

Câu trả lời:


210

Bạn có thể sử dụng Map.prototype.forEach((value, key, map) => void, thisArg?) : voidthay thế

Sử dụng nó như thế này:

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

15
Chỉ cần chạy vào đây. Không có vẻ như TypeScript đang tôn trọng thông số kỹ thuật cho việc lặp lại bản đồ, ít nhất là theo MDN chỉ định vòng lặp for. .forEachlà tối ưu, vì bạn không thể phá vỡ nó, AFAIK
Samjones

14
dunno tại sao giá trị của nó sau đó quan trọng. Có vẻ ngược.
Paul Rooney

@PaulRooney có lẽ như vậy để hòa hợp với Array.prototype.map.
Ahmed Fasih

1
Làm thế nào để dừng quá trình lặp này nếu chúng ta tìm thấy những gì chúng ta cần?
JavaRunner

36

Chỉ cần sử dụng Array.from()phương thức để chuyển đổi nó thành Array:

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

5
Chuyển đổi bản đồ là một hoạt động rất hiệu năng và không phải là cách chính xác để giải quyết vấn đề mà về cơ bản chỉ là trình biên dịch ẩn các phần cốt lõi của ngôn ngữ. Chỉ cần hiển <any>thị bản đồ để lặp lại với for-of.
Lò nung

1
Coi chừng: Tôi nghĩ rằng đề xuất của @Kilves ở trên để đưa Bản đồ thành "bất kỳ" là một cách giải quyết thanh lịch. Khi tôi làm điều đó, mã được biên dịch và chạy mà không có khiếu nại, nhưng Bản đồ không thực sự được lặp lại - nội dung của vòng lặp không bao giờ được thực thi. Các Array.from()chiến lược đề xuất ở đây đã làm việc cho tôi.
Mactyr

Tôi cũng đã thử điều đó, nó cũng không hoạt động với tôi, điều mà thậm chí còn ngớ ngẩn khi coi nó một phần của ES6 và nên "chỉ hoạt động" trên hầu hết các trình duyệt. Nhưng tôi đoán rằng các lớp phủ góc cạnh của chúng tôi sử dụng một số mumbo jumbo ma thuật trong zone.js để làm cho nó không hoạt động, vì họ ghét ES6. Thở dài.
Lò nung

35

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
Phiên bản es6 đưa ra ở trên không được biên dịch ở chế độ nghiêm ngặt.
Stephane

Xin cảm ơn ngài.
Kitanga Nday

28

Sử dụng các hàm Array.from , Array.prototype.forEach ()mũi tên :

Lặp lại các phím :

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

Lặp lại các giá trị :

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

Lặp lại các mục :

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

2
Không chắc tại sao, tôi có bản đồ như Map <String, CustomeClass>. không có phương thức nào ở trên hoạt động trừ Array.from (myMap.values ​​()). forEach (value => console.log (value));.
Rajashree Gr

27

Điều này làm việc cho tôi. Phiên bản TypeScript: 2.8.3

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

7
Tôi đã làm điều này để hoạt động bằng cách thay đổi Object.entries (myMap) thành myMap.entries (). Tôi thích câu trả lời này vì nó tránh được các lỗi xử lý lỗi của các cuộc gọi .forEach.
bắt giữ

2
Đáng lưu ý rằng nếu targettrong của bạn tsconfiges5điều này gây ra một lỗi, nhưng với es6hoạt động chính xác. Bạn cũng có thể thực hiện for (const [key, value] of myMap)khi nhắm mục tiêues6
Benjamin Vogler

16

Theo ghi chú phát hành TypeScript 2.3 trên "Mới --downlevelIteration" :

for..of statementsCác phần tử phá hủy mảng và phân tán mảng trong các phần tử mảng, cuộc gọi và biểu thức mới hỗ trợ Symbol.iterator trong ES5 / E3 nếu có sẵn khi sử dụng --downlevelIteration

Điều này không được bật theo mặc định! Thêm "downlevelIteration": truevào tsconfig.json, hoặc chuyển --downlevelIterationcờ đến tsc, để nhận được hỗ trợ lặp đầy đủ.

Với vị trí này, bạn có thể viết for (let keyval of myMap) {...}keyvalloại sẽ tự động được suy luận.


Tại sao điều này được tắt theo mặc định? Theo cộng tác viên TypeScript @aluanhaddad ,

Nó là tùy chọn vì nó có tác động rất lớn đến kích thước của mã được tạo và có khả năng về hiệu suất, đối với tất cả việc sử dụng các lần lặp (bao gồm cả mảng).

Nếu bạn có thể nhắm mục tiêu ES2015 ( "target": "es2015"trong tsconfig.jsonhoặc tsc --target ES2015) trở lên, việc bật downlevelIterationlà không có trí tuệ, nhưng nếu bạn đang nhắm mục tiêu ES5 / ES3, bạn có thể điểm chuẩn để đảm bảo hỗ trợ trình lặp không ảnh hưởng đến hiệu suất (nếu có, bạn có thể tốt hơn tắt với Array.fromchuyển đổi forEachhoặc một số cách giải quyết khác).


Điều này có ổn hay nguy hiểm khi kích hoạt điều này khi sử dụng Angular không?
Simon_Weaver

9

Điều này làm việc cho tôi.

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

2
Với điều này, các phím sẽ luôn là chuỗi mặc dù
Ixx

8

Tôi đang sử dụng TS và nút mới nhất (v2.6 và v8.9 tương ứng) và tôi có thể làm:

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

Bạn có thể xác nhận rằng trước tiên bạn phải thiết lập "downlevelIteration": truetrong của bạn tsconfig.json?
Ahmed Fasih

3
Tôi chưa downlevelIteratonđặt, mục tiêu của tôi là es2017tuy nhiên.
lazieburd

Tôi không thể làm điều này cho phần tử Map <string, CustomClass []>? trình biên dịch nói rằng nó không phải là một mảng kiểu hoặc kiểu chuỗi.
Rajashree Gr

điều này không hiệu quả với tôi vào ngày 2.8 - tôi hiểuType 'Map<K, V>' is not an array type or a string type.
Simon_Weaver

3

Bạn cũng có thể áp dụng phương thức bản đồ mảng cho iterable Map.entries ():

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

Ngoài ra, như đã lưu ý trong các câu trả lời khác, bạn có thể phải bật lặp lại cấp độ trong tsconfig.json (trong tùy chọn trình biên dịch):

  "downlevelIteration": true,

Tính năng này đã được giới thiệu trong TypeScript 2.3. Vấn đề xảy ra với nguyên cảo 1.8.10
MWe

Nếu bạn không thể sử dụng "downlevelIteration", bạn có thể sử dụng:const projected = Array.from(myMap).map(...);
Efrain

1

Chỉ cần một lời giải thích đơn giản để sử dụng nó trong một tài liệu HTML.

Nếu bạn có Bản đồ các loại (khóa, mảng) thì bạn khởi tạo mảng theo cách này:

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

Và để lặp lại nó, bạn tạo một mảng từ các giá trị chính.

Chỉ cần sử dụng nó như là một mảng như trong:

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

Sau đó, trong HTML, bạn có thể sử dụng:

*ngFor="let key of keys"

Trong vòng lặp này, bạn chỉ cần lấy giá trị mảng với:

this.cityShop.get(key)

Làm xong!


1

Trên Bản in 3.5 và Angular 8 LTS, cần phải chọn loại như sau:

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

-1

Nếu bạn không thực sự thích các hàm lồng nhau, bạn cũng có thể lặp lại các phím:

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

Lưu ý, bạn phải lọc ra các lần lặp không chính với hasOwnProperty, nếu bạn không làm điều này, bạn sẽ nhận được cảnh báo hoặc lỗi.


Làm thế nào để lặp lại trên bản đồ trong html? nó dường như không hoạt động <div ng-repeat = "(khóa, giá trị) trong model.myMap"> {{key}}. </ div>
Shinya Koizumi

@ powerfade917 Nó không hoạt động, nó chỉ hoạt động cho các mảng vì góc là một đống rác. Nhưng hãy hỏi điều này như một câu hỏi mới và vì vậy bạn sẽ học được, góc cạnh đó không phải là một đống rác, mà bạn phải chuyển đổi nó thành một mảng. Lưu ý, bạn cũng không phải là người đứng đầu trong chương trình, bởi vì bạn dường như không có khả năng phân biệt giữa góc và bản thảo.
peterh - Phục hồi Monica
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.