web-dev-qa-db-ja.com

イテレーターでmap()を使用する

Mapがあるとします:let m = new Map();m.values()を使用すると、マップ反復子が返されます。

しかし、そのイテレータでforEach()またはmap()を使用することはできず、ES6はmap()のような機能を提供するため、イテレータでwhileループを実装することはアンチパターンのようです。

では、イテレータでmap()を使用する方法はありますか?

60
shinzou

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)に移動します。 mMapであり、無限にすることはできないため、無限のシーケンスを心配する必要はありません。ほとんどの場合、これで十分です。

マップをループするには、他にもいくつかの方法があります。

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
52
ktilcu

これをループする別のイテレータ関数を定義できます。

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を使用するだけで十分です。

15
sheean

この最も簡単で最もパフォーマンスの高い方法は、 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回繰り返し、パフォーマンスが低下します。

3

反復可能オブジェクトの反復子を取得し、各反復要素でマッピングコールバック関数を呼び出す別の反復子を返すことができます。

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
2
MartyO256

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();
0
dimadeveatii