2015-06-27 17 views
45

Come lo faresti? Istintivamente, voglio fare:.map() a Javascript ES6 Mappa?

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 } 

ho non ho spigolato molto dal documentation on the new iteration protocol.

Sono consapevole del wu.js, ma sto correndo un progetto Babel e non vogliono includere Traceur, che it seems like it currently depends on.

Sono anche un po 'incapace di estrarre how fitzgen/wu.js did it nel mio progetto.

Mi piacerebbe una spiegazione chiara e concisa di ciò che mi manca qui. Grazie!


Docs for ES6 Map, FYI

+0

Sei in grado di usare 'Array.from'? – Ryan

+0

@minitech Forse, con un [polyfill] (http://babeljs.io/docs/advanced/caveats/) ... non c'è un modo per farlo senza di esso? – neezer

+0

Bene, potresti scrivere la tua funzione 'map' da usare su iterabili, usando' for of'. – Ryan

risposta

35

Così .map si offre solo un valore a cui tieni ... Detto questo, ci sono alcuni modi di affrontare questo:

// 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); 
} 

nota, ho sto usando un sacco di roba nuova nel secondo esempio ... ... Array.from prende qualsiasi iterabile (ogni volta che useresti [].slice.call(), oltre a Set e Mappe) e lo trasforma in un array ... ... Le mappe, quando costruite in un array, si trasformano in una matrice di array, dove el[0] === key && el[1] === value; (in pratica, nello stesso formato in cui ho precompilato il mio esempio Map with, above).

Uso la destrutturazione dell'array nella posizione dell'argomento del lambda, per assegnare tali punti di matrice ai valori, prima di restituire un oggetto per ciascun punto.

Se si utilizza Babel, in produzione, sarà necessario utilizzare il polyfill del browser di Babel (che include "core-js" e "rigeneratore" di Facebook).
Sono abbastanza sicuro che contenga Array.from.

+0

Sì, mi sono accorto che ho bisogno di 'Array.from' per fare questo. Il tuo primo esempio non restituisce un array, btw. – neezer

+0

@neezer no, non è così. '.forEach' restituisce' undefined' flat out, sempre, in quanto l'uso previsto di 'forEach' è una semplice iterazione basata sugli effetti collaterali (come è stato da ES5). Per usare quel 'forEach', vorrai costruire un array e popolarlo a mano, sia attraverso detto' forEach' che tramite l'iteratore restituito da '.entries()' o '.keys()' o ' .values ​​() '. 'Array.from' non sta facendo nulla di bizzarro, bensì solo nascondendo quella particolare bruttezza nel fare la traversata. E sì, controlla che includendo 'babel-core/browser.js' (o qualunque cosa sia) ottieni' .from' ... – Norguard

+1

Vedi la mia risposta, 'Array.from' prende una funzione mappa come parametro, tu non è necessario creare un array temporaneo solo per mapparlo e scartarlo. – loganfsmyth

16

Si dovrebbe solo utilizzare Spread operador:

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]

+1

... sacra schifezza, perché non ricordo che lo spread funziona su tutti gli iterabili ... – Norguard

+0

Look come richiede ancora 'Array.from', FYI. – neezer

+1

@neezer tu, assolutamente, positivamente * devi * usare il polyfill di Babel, in modo da utilizzare il codice trasposto Babel sulla tua pagina, in produzione. Non c'è modo di aggirarlo, a meno che tu non implementi tutti questi metodi (incluso Facebook Regenerator) da solo, a mano ... – Norguard

11

Basta usare Array.from(iterable, [mapFn]).

var myMap = new Map([["thing1", 1], ["thing2", 2], ["thing3", 3]]); 

var newArr = Array.from(myMap.values(), value => value + 1); 
0

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 }

0

Utilizzando Array.from ho scritto una funzione tipografico che mappa i valori:

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 } 
0

Se non si desidera convertire l'intera mappa in un array in anticipo , e/o destrutturare matrici di valori-chiave, è possibile utilizzare questa funzione stupida:

/** 
 
* 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