2015-06-27 13 views
45

Wie würden Sie das tun? Instinktiv will ich tun:.map() eine Javascript ES6 Karte?

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 } 

Ich habe noch nicht viel von der documentation on the new iteration protocol entnommen.

Ich kenne wu.js, aber ich bin ein Babel Projekt laufen und wollen nicht Traceur enthalten, die it seems like it currently depends on.

Ich bin auch ein bisschen ratlos, wie man how fitzgen/wu.js did it in mein eigenes Projekt extrahiert.

Ich würde gerne eine klare, prägnante Erklärung dafür bekommen, was mir hier fehlt. Vielen Dank!


Docs for ES6 Map, FYI

+0

Sind Sie in der Lage 'Array.from' zu benutzen? – Ryan

+0

@minitech Möglicherweise, mit einer [Polyfill] (http://babeljs.io/docs/advanced/caveats/) ... gibt es keinen Weg, dies ohne zu tun? – neezer

+0

Nun, Sie könnten Ihre eigenen 'map' -Funktion für die Verwendung auf iterables schreiben, mit' for of'. – Ryan

Antwort

35

So .map selbst bietet nur einen Wert Sie interessieren ... Das heißt, es gibt ein paar Möglichkeiten, dies anzugehen:

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

Hinweis, ich Ich benutze viele neue Sachen in diesem zweiten Beispiel ... ... Array.from nimmt alle iterierbaren (jederzeit [].slice.call(), plus Sets und Maps) und verwandelt es in ein Array ... ... Maps werden, wenn sie in ein Array gezwungen werden, zu einem Array von Arrays, wobei el[0] === key && el[1] === value; (im Grunde genommen im selben Format, in dem ich meine Beispielkarte mit, oben, vorgefüllt hatte).

Ich verwende Destrukturierung des Arrays in der Argumentposition des Lambda, um diese Array-Spots zu Werten zuzuordnen, bevor ein Objekt für jedes el zurückgegeben wird.

Wenn Sie Babel verwenden, müssen Sie in der Produktion den Babel-Polyfill verwenden (der "core-js" und den "Regenerator" von Facebook enthält).
Ich bin mir ziemlich sicher, dass es Array.from enthält.

+0

Ja, ich merke nur, dass es so aussieht, als würde ich 'Array.from' brauchen, um dies zu tun. Ihr erstes Beispiel gibt kein Array zurück. – neezer

+0

@neezer nein, tut es nicht. '.forEach' gibt' undefined' immer wieder aus, da die erwartete Verwendung von 'forEach' eine einfache Nebeneffekt-basierte Iteration ist (genau wie seit ES5). Um 'forEach' zu verwenden, sollten Sie ein Array erstellen und von Hand füllen, entweder durch' forEach' oder durch den von '.entries()' oder '.keys()' oder 'zurückgegebenen Iterator .values ​​() '. 'Array.from' macht nichts Sinnesgebendes einzigartig, es versteckt nur diese besondere Hässlichkeit des Durchfahrens. Und ja, überprüfe, ob du mit 'babel-core/browser.js' (oder was auch immer es ist) '.from' ... – Norguard

+1

Siehe meine Antwort,' Array.from' nimmt eine Map-Funktion als Parameter, du Sie müssen kein temporäres Array erstellen, nur um es zu überlagern und zu verwerfen. – loganfsmyth

16

sollten Sie verwenden nur 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

... Heiliger Mist, warum habe ich mich nicht daran erinnert, dass Spread auf allen Iterablen funktioniert ... – Norguard

+0

Sieht aus wie es noch 'Array.from' erfordert, FYI. – neezer

+1

@neezer Sie absolut, positiv * müssen * Babel's Polyfill verwenden, um Babel-transpiled Code auf Ihrer Seite in der Produktion zu verwenden. Es gibt keinen Weg, es sei denn, Sie implementieren alle diese Methoden (einschließlich Facebooks Regenerator) selbst, von Hand ... – Norguard

11

Nur Array.from(iterable, [mapFn]) verwenden.

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

Array.from Mit schrieb ich eine Typoskript Funktion, die die Werte abbildet:

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

Wenn Sie nicht möchten, dass die gesamte Karte in ein Array konvertieren vorher und/oder Struktur-Schlüssel-Wert-Arrays, können Sie diese alberne Funktion verwenden:

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