Mapがあるとします:let m = new Map();
、m.values()
を使用すると、マップ反復子が返されます。
しかし、そのイテレータでforEach()
またはmap()
を使用することはできず、ES6はmap()
のような機能を提供するため、イテレータでwhileループを実装することはアンチパターンのようです。
では、イテレータでmap()
を使用する方法はありますか?
simplestおよびleast performanceantの方法は次のとおりです。
Array.from(m).map(([key,value]) => /* whatever */)
まだ良い
Array.from(m, ([key, value]) => /* whatever */))
Array.from
は、反復可能または配列のようなものを受け取り、配列に変換します!ダニエルがコメントで指摘しているように、マッピング関数を変換に追加して、反復とその後の中間配列を削除できます。
__hrabanがコメントで指摘しているように、Array.from
を使用すると、パフォーマンスがO(1)
からO(n)
に移動します。 m
はMap
であり、無限にすることはできないため、無限のシーケンスを心配する必要はありません。ほとんどの場合、これで十分です。
マップをループするには、他にもいくつかの方法があります。
forEach
を使用m.forEach((value,key) => /* stuff */ )
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
これをループする別のイテレータ関数を定義できます。
function* generator() {
for(let i = 0; i < 10; i++) {
console.log(i);
yield i;
}
}
function* mapIterator(iterator, mapping) {
while (true) {
let result = iterator.next();
if (result.done) {
break;
}
yield mapping(result.value);
}
}
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(','));
今、あなたは尋ねるかもしれません:代わりにArray.from
を単に使用しないのはなぜですか?これはイテレータ全体を実行するため、(一時)配列に保存し、再度反復してthenマッピングを行います。リストが膨大な場合(または潜在的に無限である場合)、これは不必要なメモリ使用につながります。
もちろん、アイテムのリストがかなり小さい場合は、Array.from
を使用するだけで十分です。
この最も簡単で最もパフォーマンスの高い方法は、 Array.from
の2番目の引数を使用してこれを実現することです。
const map = new Map()
map.set('a', 1)
map.set('b', 2)
Array.from(map, ([key, value]) => `${key}:${value}`)
// ['a:1', 'b:2']
このアプローチは、反復可能なあらゆるnon-infiniteに対して機能します。また、Array.from(map).map(...)
への個別の呼び出しを使用する必要がなくなります。この呼び出しは、反復可能オブジェクトを2回繰り返し、パフォーマンスが低下します。
反復可能オブジェクトの反復子を取得し、各反復要素でマッピングコールバック関数を呼び出す別の反復子を返すことができます。
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
itiriri を使用して、イテラブルの配列のようなメソッドを実装できます。
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();