Comment ferais-tu ceci? Instinctivement, je veux faire:
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 }
Je n'ai pas beaucoup glané de la documentation sur le nouveau protocole d'itération .
Je connais wu.js , mais je dirige un projet Babel et je ne veux pas inclure Traceur , dont il semble dépendre actuellement .
Je ne sais pas non plus comment extraire comment fitzgen / wu.js l'a fait dans mon propre projet.
J'adorerais une explication claire et concise de ce qui me manque ici. Merci!
Docs pour ES6 Map , FYI
javascript
ecmascript-6
neezer
la source
la source
Array.from
?map
fonction à utiliser sur les itérables, en utilisantfor of
.Réponses:
Donc,
.map
elle-même n'offre qu'une valeur qui vous tient à cœur ... Cela dit, il existe plusieurs façons de résoudre ce problème:// 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); }
Notez que j'utilise beaucoup de nouvelles choses dans ce deuxième exemple ... ...
Array.from
prend tout itérable (à tout moment que vous utiliseriez[].slice.call( )
, plus Ensembles et Cartes) et le transforme en un tableau ... ... Cartes , lorsqu'il est contraint dans un tableau, se transforme en un tableau de tableaux, oùel[0] === key && el[1] === value;
(essentiellement, dans le même format que j'ai prérempli mon exemple de carte avec, ci-dessus).J'utilise la déstructuration du tableau dans la position d'argument du lambda, pour attribuer ces points de tableau à des valeurs, avant de renvoyer un objet pour chaque el.
Si vous utilisez Babel, en production, vous allez devoir utiliser le polyfill du navigateur de Babel (qui inclut "core-js" et le "régénérateur" de Facebook).
Je suis certain qu'il contient
Array.from
.la source
Array.from
pour faire ça. Votre premier exemple ne renvoie pas de tableau, btw..forEach
retourne àundefined
plat, tout le temps, car l'utilisation prévue deforEach
est une simple itération basée sur les effets secondaires (comme elle l'a été depuis ES5). Pour utiliser celaforEach
, vous voudrez créer un tableau et le remplir à la main, soit via leditforEach
soit via l'itérateur retourné par.entries()
ou.keys( )
ou.values( )
.Array.from
ne fait rien d'extraordinaire unique, c'est juste cacher cette laideur particulière de faire ladite traversée. Et oui, vérifiez qu'en incluantbabel-core/browser.js
(ou quoi que ce soit) vous obtenez.from
...Array.from
prend une fonction de carte comme paramètre, vous n'avez pas besoin de créer un tableau temporaire juste pour mapper dessus et le supprimer.const obj = { x: 1 };
, quand tu écris un bloc de code, tu écrisif (...) { /* block */ }
, quand tu écris une fonction fléchée que tu écris() => { return 1; }
, alors comment sait-il quand c'est un corps de fonction, par rapport aux accolades d'un objet? Et la réponse est entre parenthèses. Sinon, il s'attend à ce que le nom soit une étiquette pour un bloc de code, une fonctionnalité rarement utilisée, mais vous pouvez étiqueter uneswitch
ou une boucle, de sorte que vous puissiez enbreak;
sortir par nom. Donc, s'il manque, vous avez un corps de fonction, avec une étiquette, et l'instruction1
, basée sur l'exemple MDNVous devez simplement utiliser l' opérateur 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]
la source
Array.from
, FYI.[...myMap].map(mapFn)
va créer un tableau temporaire, puis le supprimer.Array.from
prend amapFn
comme deuxième argument, utilisez-le simplement.Array.from(myMap.values(), val => val + 1);
?Utilisez juste
Array.from(iterable, [mapFn])
.var myMap = new Map([["thing1", 1], ["thing2", 2], ["thing3", 3]]); var newArr = Array.from(myMap.values(), value => value + 1);
la source
Array.from()
pris une fonction de cartographie comme deuxième paramètre facultatif.Vous pouvez utiliser cette fonction:
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 } */
la source
En utilisant,
Array.from
j'ai écrit une fonction Typescript qui mappe les valeurs: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 }
la source
En fait, vous pouvez toujours avoir un
Map
avec les clés d'origine après la conversion en tableau avecArray.from
. C'est possible en renvoyant un tableau , où le premier élément est lekey
, et le second est le transformé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 }
Si vous ne renvoyez pas cette clé comme premier élément du tableau, vous perdez vos
Map
clés.la source
Je préfère étendre la carte
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; }; }
la source
Vous pouvez utiliser myMap.forEach, et dans chaque boucle, utiliser map.set pour modifier la valeur.
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); }
la source
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 }
la source
Si vous ne voulez pas convertir au préalable la carte entière en un tableau et / ou déstructurer des tableaux clé-valeur, vous pouvez utiliser cette fonction idiote:
/** * 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
la source
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)
Cela dépend de votre ferveur religieuse pour éviter de modifier des prototypes, mais je trouve que cela me permet de rester intuitif.
la source
Vous pouvez mapper des tableaux (), mais cette opération n'existe pas pour Maps. La solution du Dr Axel Rauschmayer :
Exemple:
let map0 = new Map([ [1, "a"], [2, "b"], [3, "c"] ]); const map1 = new Map( [...map0] .map(([k, v]) => [k * 2, '_' + v]) );
abouti à
{2 => '_a', 4 => '_b', 6 => '_c'}
la source
Peut-être de cette façon:
const m = new Map([["a", 1], ["b", 2], ["c", 3]]); m.map((k, v) => [k, v * 2]); // Map { 'a' => 2, 'b' => 4, 'c' => 6 }
Vous n'auriez besoin que de monkey patch
Map
avant:Map.prototype.map = function(func){ return new Map(Array.from(this, ([k, v]) => func(k, v))); }
Nous aurions pu écrire une forme plus simple de ce patch:
Map.prototype.map = function(func){ return new Map(Array.from(this, func)); }
Mais nous nous aurions forcés à écrire ensuite
m.map(([k, v]) => [k, v * 2]);
ce qui me paraît un peu plus douloureux et laid.Mappage des valeurs uniquement
Nous pourrions également mapper uniquement les valeurs, mais je ne conseillerais pas d'opter pour cette solution car elle est trop spécifique. Néanmoins, cela peut être fait et nous aurions l'API suivante:
const m = new Map([["a", 1], ["b", 2], ["c", 3]]); m.map(v => v * 2); // Map { 'a' => 2, 'b' => 4, 'c' => 6 }
Juste comme avant de patcher de cette façon:
Map.prototype.map = function(func){ return new Map(Array.from(this, ([k, v]) => [k, func(v)])); }
Peut-être que vous pouvez avoir les deux, en nommant le second
mapValues
pour indiquer clairement que vous ne mappez pas réellement l'objet comme on s'y attendrait probablement.la source