[英].map() a Javascript ES6 Map?
How would you do this?你会怎么做? Instinctively, I want to do:
本能地,我想做:
var myMap = new Map([["thing1", 1], ["thing2", 2], ["thing3", 3]]);
// wishful, ignorant thinking
var newMap = myMap.map((key, value) => value + 1); // Map { 'thing1' => 2, 'thing2' => 3, 'thing3' => 4 }
I've haven't gleaned much from the documentation on the new iteration protocol .我没有从有关新迭代协议的文档中收集到太多信息。
I am aware of wu.js , but I'm running a Babel project and don't want to include Traceur , which it seems like it currently depends on .我知道wu.js ,但我正在运行一个Babel项目并且不想包含Traceur ,它似乎目前依赖于.
I also am a bit clueless as to how to extract how fitzgen/wu.js did it into my own project.对于如何将fitzgen/wu.js如何提取到我自己的项目中,我也有点不知所措。
Would love a clear, concise explanation of what I'm missing here.希望对我在这里缺少的内容进行清晰,简洁的解释。 Thanks!
谢谢!
Docs for ES6 Map , FYI ES6 Map 的文档,仅供参考
So .map
itself only offers one value you care about... That said, there are a few ways of tackling this:所以
.map
本身只提供你关心的一个值......也就是说,有几种方法可以解决这个问题:
// instantiation
const myMap = new Map([
[ "A", 1 ],
[ "B", 2 ]
]);
// what's built into Map for you
myMap.forEach( (val, key) => console.log(key, val) ); // "A 1", "B 2"
// what Array can do for you
Array.from( myMap ).map(([key, value]) => ({ key, value })); // [{key:"A", value: 1}, ... ]
// less awesome iteration
let entries = myMap.entries( );
for (let entry of entries) {
console.log(entry);
}
Note, I'm using a lot of new stuff in that second example... ... Array.from
takes any iterable (any time you'd use [].slice.call( )
, plus Sets and Maps) and turns it into an array... ...Maps, when coerced into an array, turn into an array of arrays, where el[0] === key && el[1] === value;
注意,我在第二个例子中使用了很多新东西...... ...
Array.from
接受任何迭代(任何时候你使用[].slice.call( )
,加上 Sets 和 Maps)并轮流把它变成数组... ...Maps,当强制变成数组时,变成数组的数组,其中el[0] === key && el[1] === value;
(basically, in the same format that I prefilled my example Map with, above). (基本上,与我在上面预填充示例 Map 的格式相同)。
I'm using destructuring of the array in the argument position of the lambda, to assign those array spots to values, before returning an object for each el.我在 lambda 的参数位置使用数组的解构,将这些数组点分配给值,然后为每个 el 返回一个对象。
If you're using Babel, in production, you're going to need to use Babel's browser polyfill (which includes "core-js" and Facebook's "regenerator").如果您在生产环境中使用 Babel,您将需要使用 Babel 的浏览器 polyfill(包括“core-js”和 Facebook 的“regenerator”)。
I'm quite certain it contains Array.from
.我很确定它包含
Array.from
。
You should just use Spread operator :您应该只使用Spread 运算符:
var myMap = new Map([["thing1", 1], ["thing2", 2], ["thing3", 3]]); var newArr = [...myMap].map(value => value[1] + 1); console.log(newArr); //[2, 3, 4] var newArr2 = [for(value of myMap) value = value[1] + 1]; console.log(newArr2); //[2, 3, 4]
Just use Array.from(iterable, [mapFn])
.只需使用
Array.from(iterable, [mapFn])
。
var myMap = new Map([["thing1", 1], ["thing2", 2], ["thing3", 3]]);
var newEntries = Array.from(myMap, ([key, value]) => [key, value + 1]);
var newMap = new Map(newEntries);
You can use this function:您可以使用此功能:
function mapMap(map, fn) {
return new Map(Array.from(map, ([key, value]) => [key, fn(value, key, map)]));
}
usage:用法:
var map1 = new Map([["A", 2], ["B", 3], ["C", 4]]);
var map2 = mapMap(map1, v => v * v);
console.log(map1, map2);
/*
Map { A → 2, B → 3, C → 4 }
Map { A → 4, B → 9, C → 16 }
*/
Using Array.from
I wrote a Typescript function that maps the values:使用
Array.from
我写了一个 Typescript 函数来映射这些值:
function mapKeys<T, V, U>(m: Map<T, V>, fn: (this: void, v: V) => U): Map<T, U> {
function transformPair([k, v]: [T, V]): [T, U] {
return [k, fn(v)]
}
return new Map(Array.from(m.entries(), transformPair));
}
const m = new Map([[1, 2], [3, 4]]);
console.log(mapKeys(m, i => i + 1));
// Map { 1 => 3, 3 => 5 }
Actually you can still have a Map
with the original keys after converting to array with Array.from
.其实你仍然可以有一个
Map
与原来的键转换成数组后Array.from
。 That's possible by returning an array , where the first item is the key
, and the second is the transformed value
.这可以通过返回一个array 来实现,其中第一项是
key
,第二项是转换后的value
。
const originalMap = new Map([
["thing1", 1], ["thing2", 2], ["thing3", 3]
]);
const arrayMap = Array.from(originalMap, ([key, value]) => {
return [key, value + 1]; // return an array
});
const alteredMap = new Map(arrayMap);
console.log(originalMap); // Map { 'thing1' => 1, 'thing2' => 2, 'thing3' => 3 }
console.log(alteredMap); // Map { 'thing1' => 2, 'thing2' => 3, 'thing3' => 4 }
If you don't return that key as the first array item, you loose your Map
keys.如果您不将该键作为第一个数组项返回,就会丢失您的
Map
键。
You can map() arrays, but there is no such operation for Maps.您可以 map() 数组,但 Maps 没有这样的操作。 The solution from Dr. Axel Rauschmayer :
Axel Rauschmayer 博士的解决方案:
Example:例子:
let map0 = new Map([
[1, "a"],
[2, "b"],
[3, "c"]
]);
const map1 = new Map(
[...map0]
.map(([k, v]) => [k * 2, '_' + v])
);
resulted in导致
{2 => '_a', 4 => '_b', 6 => '_c'}
I prefer to extend the map我更喜欢扩展地图
export class UtilMap extends Map {
constructor(...args) { super(args); }
public map(supplier) {
const mapped = new UtilMap();
this.forEach(((value, key) => mapped.set(key, supplier(value, key)) ));
return mapped;
};
}
You can use myMap.forEach, and in each loop, using map.set to change value.您可以使用 myMap.forEach,并在每个循环中使用 map.set 更改值。
myMap = new Map([ ["a", 1], ["b", 2], ["c", 3] ]); for (var [key, value] of myMap.entries()) { console.log(key + ' = ' + value); } myMap.forEach((value, key, map) => { map.set(key, value+1) }) for (var [key, value] of myMap.entries()) { console.log(key + ' = ' + value); }
const mapMap = (callback, map) => new Map(Array.from(map).map(callback)) var myMap = new Map([["thing1", 1], ["thing2", 2], ["thing3", 3]]); var newMap = mapMap((pair) => [pair[0], pair[1] + 1], myMap); // Map { 'thing1' => 2, 'thing2' => 3, 'thing3' => 4 }
If you don't want to convert the entire Map into an array beforehand, and/or destructure key-value arrays, you can use this silly function:如果您不想事先将整个 Map 转换为数组,和/或解构键值数组,则可以使用这个愚蠢的函数:
/** * Map over an ES6 Map. * * @param {Map} map * @param {Function} cb Callback. Receives two arguments: key, value. * @returns {Array} */ function mapMap(map, cb) { let out = new Array(map.size); let i = 0; map.forEach((val, key) => { out[i++] = cb(key, val); }); return out; } let map = new Map([ ["a", 1], ["b", 2], ["c", 3] ]); console.log( mapMap(map, (k, v) => `${k}-${v}`).join(', ') ); // a-1, b-2, c-3
Map.prototype.map = function(callback) {
const output = new Map()
this.forEach((element, key)=>{
output.set(key, callback(element, key))
})
return output
}
const myMap = new Map([["thing1", 1], ["thing2", 2], ["thing3", 3]])
// no longer wishful thinking
const newMap = myMap.map((value, key) => value + 1)
console.info(myMap, newMap)
Depends on your religious fervor in avoiding editing prototypes, but, I find this lets me keep it intuitive.取决于您避免编辑原型的宗教热情,但是,我发现这可以让我保持直观。
In typescript, in case somebody would need it :在打字稿中,以防有人需要它:
export {}
declare global {
interface Map<K, V> {
map<T>(predicate: (key: K, value: V) => T): Map<V, T>
}
}
Map.prototype.map = function<K, V, T>(predicate: (value: V, key: K) => T): Map<K, T> {
let map: Map<K, T> = new Map()
this.forEach((value: V, key: K) => {
map.set(key, predicate(value, key))
})
return map
}
Here is a Typescript variant which builds upon some of the existing ideas and attempts to be flexible in the following ways:这是一个 Typescript 变体,它建立在一些现有想法的基础上,并尝试通过以下方式变得灵活:
function mapMap<TKI, TVI, TKO, TVO>(map: Map<TKI, TVI>,
f: (k: TKI, v: TVI, m: Map<TKI, TVI>) => [TKO, TVO]) : Map<TKO, TVO>{
return new Map([...map].map(p => f(p[0], p[1], map)))
}
Note: this code uses the spread operator, like some of the existing ideas, and so needs a target of of 'es2015' or higher
according to my VS Code Intellisense.注意:此代码使用扩展运算符,就像一些现有的想法一样,因此根据我的 VS Code Intellisense 需要一个
of 'es2015' or higher
的目标。
Maybe this way:也许这样:
const m = new Map([["a", 1], ["b", 2], ["c", 3]]);
m.map((k, v) => [k, v * 2]); // Map { 'a' => 2, 'b' => 4, 'c' => 6 }
You would only need to monkey patch Map
before:您只需要在之前对
Map
进行猴子补丁:
Map.prototype.map = function(func){
return new Map(Array.from(this, ([k, v]) => func(k, v)));
}
We could have wrote a simpler form of this patch:我们本可以编写一个更简单的补丁形式:
Map.prototype.map = function(func){
return new Map(Array.from(this, func));
}
But we would have forced us to then write m.map(([k, v]) => [k, v * 2]);
但是我们会强迫我们写
m.map(([k, v]) => [k, v * 2]);
which seems a bit more painful and ugly to me.这对我来说似乎更痛苦和丑陋。
We could also map values only, but I wouldn't advice going for that solution as it is too specific.我们也可以只映射值,但我不建议采用该解决方案,因为它太具体了。 Nevertheless it can be done and we would have the following API:
尽管如此,它可以完成,我们将拥有以下 API:
const m = new Map([["a", 1], ["b", 2], ["c", 3]]);
m.map(v => v * 2); // Map { 'a' => 2, 'b' => 4, 'c' => 6 }
Just like before patching this way:就像在以这种方式修补之前一样:
Map.prototype.map = function(func){
return new Map(Array.from(this, ([k, v]) => [k, func(v)]));
}
Maybe you can have both, naming the second mapValues
to make it clear that you are not actually mapping the object as it would probably be expected.也许您可以同时拥有两者,命名第二个
mapValues
以表明您实际上并没有像预期的那样映射对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.