Katakanlah kita memiliki Peta :, let m = new Map();
menggunakan m.values()
mengembalikan iterator peta.
Tetapi saya tidak dapat menggunakan forEach()
atau map()
pada iterator itu dan mengimplementasikan loop sementara pada iterator itu tampak seperti anti-pola karena ES6 menawarkan fungsi seperti map()
.
Jadi, apakah ada cara untuk menggunakan map()
iterator?
javascript
dictionary
syntax
ecmascript-6
iterator
shinzou
sumber
sumber
lodash
map
fungsi yang mendukung Peta juga.Array.from(m.values()).map(...)
berhasil, tetapi saya pikir itu bukan cara terbaik untuk melakukan ini.Array#map
?Jawaban:
Cara termudah dan paling tidak berkinerja untuk melakukan ini adalah:
Array.from(m).map(([key,value]) => /* whatever */)
Lebih baik
Array.from(m, ([key, value]) => /* whatever */))
Array.from
mengambil hal yang dapat diulang atau seperti larik dan mengubahnya menjadi larik! Seperti yang Daniel tunjukkan di komentar, kita dapat menambahkan fungsi pemetaan ke konversi untuk menghapus iterasi dan selanjutnya array perantara.Menggunakan
Array.from
akan bergerak kinerja Anda dariO(1)
keO(n)
sebagai titik @hraban keluar di komentar. Karenam
adalah aMap
, dan mereka tidak bisa tidak terbatas, kita tidak perlu khawatir tentang urutan yang tidak terbatas. Untuk kebanyakan kasus, ini sudah cukup.Ada beberapa cara lain untuk memutar melalui peta.
Menggunakan
forEach
m.forEach((value,key) => /* stuff */ )
Menggunakan
for..of
var myMap = new Map(); myMap.set(0, 'zero'); myMap.set(1, 'one'); for (var [key, value] of myMap) { console.log(key + ' = ' + value); } // 0 = zero // 1 = one
sumber
Array.from(m, ([key,value]) => /* whatever */)
(perhatikan fungsi pemetaan ada di dalamfrom
) dan kemudian tidak ada larik perantara yang dibuat ( sumber ). Ini masih berpindah dari O (1) ke O (n), tetapi setidaknya iterasi dan pemetaan terjadi hanya dalam satu iterasi penuh.Anda dapat menentukan fungsi iterator lain untuk mengulang ini:
function* generator() { for (let i = 0; i < 10; i++) { console.log(i); yield i; } } function* mapIterator(iterator, mapping) { for (let i of iterator) { yield mapping(i); } } let values = generator(); let mapped = mapIterator(values, (i) => { let result = i*2; console.log(`x2 = ${result}`); return result; }); console.log('The values will be generated right now.'); console.log(Array.from(mapped).join(','));
Sekarang Anda mungkin bertanya: mengapa tidak menggunakan
Array.from
saja? Karena ini akan berjalan melalui seluruh iterator, simpan ke array (sementara), iterasikan lagi dan kemudian lakukan pemetaan. Jika daftarnya sangat besar (atau bahkan berpotensi tidak terbatas) ini akan menyebabkan penggunaan memori yang tidak perlu.Tentu saja, jika daftar item cukup kecil, penggunaan
Array.from
harus lebih dari cukup.sumber
mapIterator()
tidak menjamin bahwa iterator yang mendasari akan ditutup dengan benar (iterator.return()
dipanggil) kecuali nilai kembalian berikutnya dipanggil setidaknya sekali. Lihat: repeater.js.org/docs/safetyfor .. of .. loop
?Cara paling sederhana dan paling berhasil ini adalah dengan menggunakan argumen kedua
Array.from
untuk mencapai ini:const map = new Map() map.set('a', 1) map.set('b', 2) Array.from(map, ([key, value]) => `${key}:${value}`) // ['a:1', 'b:2']
Pendekatan ini bekerja untuk iterable non-infinite . Dan itu menghindari keharusan untuk menggunakan panggilan terpisah
Array.from(map).map(...)
yang akan mengulang melalui iterable dua kali dan lebih buruk untuk kinerja.sumber
Anda dapat mengambil iterator melalui iterable, lalu mengembalikan iterator lain yang memanggil fungsi callback pemetaan pada setiap elemen yang diiterasi.
const map = (iterable, callback) => { return { [Symbol.iterator]() { const iterator = iterable[Symbol.iterator](); return { next() { const r = iterator.next(); if (r.done) return r; else { return { value: callback(r.value), done: false, }; } } } } } }; // Arrays are iterable console.log(...map([0, 1, 2, 3, 4], (num) => 2 * num)); // 0 2 4 6 8
sumber
Anda bisa menggunakan itiriri yang mengimplementasikan metode mirip array untuk iterable:
import { query } from 'itiriri'; let m = new Map(); // set map ... query(m).filter([k, v] => k < 10).forEach([k, v] => console.log(v)); let arr = query(m.values()).map(v => v * 10).toArray();
sumber
from
fn dari "core-js-pure / features / iterator" yang mengembalikan iterator "baru".Kunjungi https://www.npmjs.com/package/fluent-iterable
Bekerja dengan semua iterable (Peta, fungsi generator, array) dan iterable async.
const map = new Map(); ... console.log(fluent(map).filter(..).map(..));
sumber
Ada proposal, yang menghadirkan beberapa fungsi pembantu ke
Iterator
: https://github.com/tc39/proposal-iterator-helpers ( dirender )Anda dapat menggunakannya hari ini dengan memanfaatkan
core-js
:import { from as iterFrom } from "core-js-pure/features/iterator"; // or if it's working for you: // import iterFrom from "core-js-pure/features/iterator/from"; let m = new Map(); m.set("13", 37); m.set("42", 42); const arr = iterFrom(m.values()) .map((val) => val * 2) .toArray(); // prints "[74, 84]" console.log(arr);
sumber
Jawaban lain di sini adalah ... Aneh. Mereka tampaknya menerapkan kembali bagian dari protokol iterasi. Anda bisa melakukan ini:
function* mapIter(iterable, callback) { for (let x of iterable) { yield callback(x); } }
dan jika ingin hasil yang konkret gunakan saja operator spread
...
.[...iterMap([1, 2, 3], x => x**2)]
sumber