Say we have a Map: let m = new Map();
, using m.values()
returns a map iterator.
But I can\'t use forEach()
or map()
o
Other answers here are... Weird. They seem to be re-implementing parts of the iteration protocol. You can just do this:
function* mapIter(iterable, callback) {
for (let x of iterable) {
yield callback(x);
}
}
and if you want a concrete result just use the spread operator ...
.
[...iterMap([1, 2, 3], x => x**2)]
You could retrieve an iterator over the iterable, then return another iterator that calls the mapping callback function on each iterated element.
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
Take a look at https://www.npmjs.com/package/fluent-iterable
Works with all of iterables (Map, generator function, array) and async iterables.
const map = new Map();
...
console.log(fluent(map).filter(..).map(..));
There is a proposal, that is bringing multiple helper functions to Iterator
: https://github.com/tc39/proposal-iterator-helpers (rendered)
You can use it today by utilizing 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);
This simplest and most performant way is to use the second argument to Array.from to achieve this:
const map = new Map()
map.set('a', 1)
map.set('b', 2)
Array.from(map, ([key, value]) => `${key}:${value}`)
// ['a:1', 'b:2']
This approach works for any non-infinite iterable. And it avoids having to use a separate call to Array.from(map).map(...)
which would iterate through the iterable twice and be worse for performance.
You could define another iterator function to loop over this:
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(','));
Now you might ask: why not just use Array.from
instead? Because this will run through the entire iterator, save it to a (temporary) array, iterate it again and then do the mapping. If the list is huge (or even potentially infinite) this will lead to unnecessary memory usage.
Of course, if the list of items is fairly small, using Array.from
should be more than sufficient.