Использование 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)
}