假设我们有一个Map :,let m = new Map();
使用会m.values()
返回一个地图迭代器。
但我不能在迭代器上使用forEach()
或map()
,并且在该迭代器上实现while循环似乎是一种反模式,因为ES6提供了的功能map()
。
那么有没有办法map()
在迭代器上使用?
假设我们有一个Map :,let m = new Map();
使用会m.values()
返回一个地图迭代器。
但我不能在迭代器上使用forEach()
或map()
,并且在该迭代器上实现while循环似乎是一种反模式,因为ES6提供了的功能map()
。
那么有没有办法map()
在迭代器上使用?
Array.from(m.values()).map(...)
,但是我认为这不是最好的方法。
Answers:
在最简单和最高性能做到这一点的方法是:
Array.from(m).map(([key,value]) => /* whatever */)
更好了
Array.from(m, ([key, value]) => /* whatever */))
Array.from
接受任何可迭代的或类似数组的东西,并将其转换为数组!正如Daniel在评论中指出的,我们可以在转换中添加一个映射函数,以删除迭代,然后删除中间数组。
@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
Array.from(m, ([key,value]) => /* whatever */)
(注意映射函数位于中from
),然后不创建任何中间数组(source)。它仍然从O(1)移到O(n),但是至少迭代和映射仅发生在一个完整的迭代中。
您可以定义另一个迭代器函数来对此进行循环:
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
呢?因为这将贯穿整个迭代器,所以将其保存到(临时)数组中,再次对其进行迭代,然后进行映射。如果列表很大(甚至可能是无限的),这将导致不必要的内存使用。
当然,如果项目列表很小,那么使用Array.from
应该绰绰有余。
这种最简单,最高效的方法是使用第二个参数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(...)
该调用将迭代可迭代两次,从而降低性能。
您可以在可迭代对象上检索一个迭代器,然后返回另一个迭代器,该迭代器在每个迭代元素上调用映射回调函数。
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();
看看https://www.npmjs.com/package/fluent-iterable
与所有可迭代项(Map,生成器函数,数组)和异步可迭代项一起使用。
const map = new Map();
...
console.log(fluent(map).filter(..).map(..));
lodash
map
也支持Map的函数。