Использование map() на итераторе

Скажем, у нас есть карта: let m = new Map();, используя m.values() возвращает итератор карты.

Но я не могу использовать forEach() или map() на этом итераторе и реализовать цикл while на этом итераторе, как анти-шаблон, поскольку ES6 предлагает такие функции, как map().

Итак, есть ли способ использовать map() на итераторе?

Ответы

Ответ 1

Самый простой и наименее производительный способ сделать это:

Array.from(m).map(([key,value]) => /* whatever */)

Еще лучше

Array.from(m, ([key, value]) => /* whatever */))

Array.from берет любую итеративную или похожую на массив вещь и преобразует ее в массив! Как указывает Даниэль в комментариях, мы можем добавить функцию преобразования в преобразование, чтобы удалить итерацию, а затем и промежуточный массив.

Использование Array.from переместит вашу производительность с O(1) на O(n) как указывает @hraban в комментариях. Поскольку 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

Ответ 2

Вы можете определить другую функцию итератора, чтобы перебрать это:

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(','));

Ответ 3

Этот самый простой и эффективный способ - использовать второй аргумент Array.from для достижения этой цели:

const map = new Map()
map.set('a', 1)
map.set('b', 2)

Array.from(map, ([key, value]) => '${key}:${value}')
// ['a:1', 'b:2']

Этот подход работает для любой бесконечной итерации. И это исключает необходимость использования отдельного вызова Array.from(map).map(...) который повторял бы итерируемое дважды и ухудшал производительность.

Ответ 4

Вы можете извлечь итератор поверх итерируемого, а затем вернуть другой итератор, который вызывает функцию обратного вызова сопоставления для каждого итеративного элемента.

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

Ответ 5

Вы можете использовать itiriri, который реализует подобные массиву методы для iterables:

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

Ответ 6

Или используйте [...m.values()].map(...)

Ответ 7

Итерация по карте

1) Итерировать по ключам карты

Map предлагает метод keys(), который мы можем использовать для перебора всех ключей.

for (const k of m.keys()) {
  console.log(k)
}

2) Итерация по значениям карты

Объект Map предлагает метод values (), который мы можем использовать для перебора всех значений:

for (const v of m.values()) {
  console.log(v)
}

3) Итерировать по ключу карты, парам значений

Объект Map предлагает метод entry(), который мы можем использовать для перебора всех значений:

for (const [k, v] of m.entries()) {
  console.log(k, v)
}

Также мы можем упростить

for (const [k, v] of m) {
  console.log(k, v)
}