Como você faria isso? Instintivamente, eu quero fazer:
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 }
Não obtive muito da documentação sobre o novo protocolo de iteração .
Estou ciente de wu.js , mas estou executando um projeto Babel e não quero incluir Traceur , do qual parece que depende atualmente .
Também não tenho ideia de como extrair como fitzgen / wu.js fez isso em meu próprio projeto.
Adoraria uma explicação clara e concisa do que estou perdendo aqui. Obrigado!
Docs for ES6 Map , FYI
javascript
ecmascript-6
neezer
fonte
fonte
Array.from
?map
função para uso em iteráveis, usandofor of
.Respostas:
Portanto,
.map
ele próprio oferece apenas um valor com o qual você se preocupa ... Dito isso, existem algumas maneiras de lidar com isso:// 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); }
Observe, estou usando muitas coisas novas naquele segundo exemplo ... ...
Array.from
pega qualquer iterável (a qualquer momento que você usaria[].slice.call( )
, mais Sets e Maps) e o transforma em um array ... ... Maps , quando coagidos em um array, se transformam em um array de arrays, ondeel[0] === key && el[1] === value;
(basicamente, no mesmo formato que eu pré-preenchi meu mapa de exemplo, acima).Estou usando a desestruturação do array na posição do argumento do lambda, para atribuir esses pontos do array a valores, antes de retornar um objeto para cada el.
Se você estiver usando o Babel, em produção, precisará usar o polyfill do navegador do Babel (que inclui "core-js" e o "regenerador" do Facebook).
Tenho certeza de que contém
Array.from
.fonte
Array.from
para fazer isso. Seu primeiro exemplo não retorna uma matriz, aliás..forEach
retornaundefined
direto, o tempo todo, pois o uso esperado deforEach
é uma iteração simples baseada em efeitos colaterais (o mesmo que tem sido desde ES5). Para usar issoforEach
, você deseja construir um array e preenchê-lo manualmente, por meio de ditoforEach
ou por meio do iterador retornado por.entries()
ou.keys( )
ou.values( )
.Array.from
não está fazendo nada extraordinariamente único, está apenas escondendo aquela feiura particular de fazer essa travessia. E sim, verifique se incluindobabel-core/browser.js
(ou seja lá o que for) você obtém.from
...Array.from
leva uma função de mapa como um parâmetro, você não precisa criar um array temporário apenas para mapear sobre ele e descartá-lo.const obj = { x: 1 };
, quando você escreve um bloco de código, você escreveif (...) { /* block */ }
, quando você escreve uma função de seta você escreve() => { return 1; }
, então como saber quando é o corpo de uma função, versus as chaves de um objeto? E a resposta está entre parênteses. Caso contrário, ele espera que o nome seja um rótulo para um bloco de código, um recurso raramente usado, mas você pode rotular umswitch
ou um loop, de modo que possabreak;
retirá-los pelo nome. Então, se estiver faltando, você tem um corpo de função, com um rótulo e a instrução1
, com base no exemplo MDNVocê deve apenas usar o operador 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]
fonte
Array.from
, FYI.[...myMap].map(mapFn)
vai criar um array temporário e, em seguida, descartá-lo.Array.from
recebe amapFn
como seu segundo argumento, basta usá-lo.Array.from(myMap.values(), val => val + 1);
?Basta usar
Array.from(iterable, [mapFn])
.var myMap = new Map([["thing1", 1], ["thing2", 2], ["thing3", 3]]); var newArr = Array.from(myMap.values(), value => value + 1);
fonte
Array.from()
uma função de mapeamento como um segundo parâmetro opcional.Map.values()
, ao contrário de Array.values () que ainda não funciona: facepalm:Você pode usar esta função:
function mapMap(map, fn) { return new Map(Array.from(map, ([key, value]) => [key, fn(value, key, map)])); }
uso:
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 } */
fonte
Usando
Array.from
, escrevi uma função Typescript que mapeia os valores: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 }
fonte
Na verdade, você ainda pode ter um
Map
com as chaves originais depois de converter para um array comArray.from
. Isso é possível retornando um array , onde o primeiro item é okey
e o segundo é o transformadovalue
.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 }
Se você não retornar essa chave como o primeiro item do array, perderá suas
Map
chaves.fonte
Eu prefiro estender o mapa
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; }; }
fonte
Você pode usar myMap.forEach e, em cada loop, usar map.set para alterar o valor.
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); }
fonte
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 }
fonte
Se você não quiser converter o Map inteiro em uma matriz de antemão e / ou desestruturar matrizes de valores-chave, você pode usar esta função boba:
/** * 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
fonte
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)
Depende do seu fervor religioso em evitar a edição de protótipos, mas acho que isso me permite mantê-lo intuitivo.
fonte
Você pode mapear matrizes (), mas não existe tal operação para Mapas. A solução do Dr. Axel Rauschmayer :
Exemplo:
let map0 = new Map([ [1, "a"], [2, "b"], [3, "c"] ]); const map1 = new Map( [...map0] .map(([k, v]) => [k * 2, '_' + v]) );
resultou em
{2 => '_a', 4 => '_b', 6 => '_c'}
fonte
Talvez desta forma:
const m = new Map([["a", 1], ["b", 2], ["c", 3]]); m.map((k, v) => [k, v * 2]); // Map { 'a' => 2, 'b' => 4, 'c' => 6 }
Você só precisa fazer o monkey patch
Map
antes de:Map.prototype.map = function(func){ return new Map(Array.from(this, ([k, v]) => func(k, v))); }
Poderíamos ter escrito uma forma mais simples deste patch:
Map.prototype.map = function(func){ return new Map(Array.from(this, func)); }
Mas teríamos nos forçado a escrever, o
m.map(([k, v]) => [k, v * 2]);
que me parece um pouco mais doloroso e feio.Somente valores de mapeamento
Também poderíamos mapear apenas valores, mas eu não recomendaria essa solução, pois é muito específica. No entanto, isso pode ser feito e teríamos a seguinte API:
const m = new Map([["a", 1], ["b", 2], ["c", 3]]); m.map(v => v * 2); // Map { 'a' => 2, 'b' => 4, 'c' => 6 }
Exatamente como antes de corrigir desta forma:
Map.prototype.map = function(func){ return new Map(Array.from(this, ([k, v]) => [k, func(v)])); }
Talvez você possa ter ambos, nomeando o segundo
mapValues
para deixar claro que você não está realmente mapeando o objeto como seria de se esperar.fonte