Как бы вы это сделали? Инстинктивно я хочу сделать:
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 }
Я не особо почерпнул из документации по новому протоколу итераций .
Мне известно о wu.js , но я запускаю проект Babel и не хочу включать Traceur , от которого, похоже, он сейчас зависит .
Я также немного не понимаю, как извлечь, как fitzgen / wu.js сделал это в мой собственный проект.
Хотелось бы четкого и краткого объяснения того, что мне здесь не хватает. Благодарность!
Документы для карты ES6 , к сведению
javascript
ecmascript-6
Neezer
источник
источник
Array.from
?map
функцию для использования с итерациями, используяfor of
.Ответы:
Таким образом,
.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); }
Обратите внимание: во втором примере я использую много нового ... ...
Array.from
берет любую итерацию (в любой момент, когда вы ее используете[].slice.call( )
, плюс наборы и карты) и превращает ее в массив ... ... Карты , при принудительном преобразовании в массив превращается в массив массивов, whereel[0] === key && el[1] === value;
(в основном, в том же формате, который я предварительно заполнил в моем примере Map выше).Я использую деструктуризацию массива в позиции аргумента лямбда-выражения, чтобы присвоить этим точкам массива значения, прежде чем возвращать объект для каждого el.
Если вы используете Babel в производственной среде, вам нужно будет использовать полифилл браузера Babel (который включает «core-js» и «регенератор» Facebook).
Я совершенно уверен, что он содержит
Array.from
.источник
Array.from
для этого. Ваш первый пример не возвращает массив, кстати..forEach
возвращаетсяundefined
, поскольку ожидается использованиеforEach
простой итерации, основанной на побочных эффектах (так же, как это было со времен ES5). Чтобы использовать этоforEach
, вам нужно создать массив и заполнить его вручную, либо с помощью указанного,forEach
либо с помощью итератора, возвращаемого.entries()
или.keys( )
или.values( )
.Array.from
не делает ничего невероятно уникального, а просто скрывает это конкретное уродство выполнения указанного обхода. И да, проверьте это, включивbabel-core/browser.js
(или что-то еще), вы получите.from
...Array.from
принимает функцию карты в качестве параметра, вам не нужно создавать временный массив, чтобы отобразить его и отбросить.const obj = { x: 1 };
, когда вы пишете блок кода, вы пишетеif (...) { /* block */ }
, когда вы пишете функцию стрелки, которую вы пишете() => { return 1; }
, так как она узнает, что это тело функции, а не фигурные скобки объекта? И ответ - круглые скобки. В противном случае он ожидает, что имя будет меткой для блока кода, который редко используется, но вы можете пометитьswitch
цикл или цикл, чтобы вы моглиbreak;
выйти из них по имени. Так что, если он отсутствует, у вас есть тело функции с меткой и оператором1
, основанным на примере MDNВам просто нужно использовать оператор 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]
источник
Array.from
, к вашему сведению.[...myMap].map(mapFn)
собирается создать временный массив, а затем отбросить его.Array.from
принимает вmapFn
качестве второго аргумента, просто используйте его.Array.from(myMap.values(), val => val + 1);
?Просто используйте
Array.from(iterable, [mapFn])
.var myMap = new Map([["thing1", 1], ["thing2", 2], ["thing3", 3]]); var newArr = Array.from(myMap.values(), value => value + 1);
источник
Array.from()
что функция сопоставления была необязательным вторым параметром.Вы можете использовать эту функцию:
function mapMap(map, fn) { return new Map(Array.from(map, ([key, value]) => [key, fn(value, key, map)])); }
Применение:
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 } */
источник
Используя,
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 }
источник
На самом деле вы все еще можете иметь
Map
исходные ключи после преобразования в массив с помощьюArray.from
. Это возможно, если вернуть массив , где первый элемент - это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 }
Если вы не вернете этот ключ в качестве первого элемента массива, вы потеряете свои
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; }; }
источник
Вы можете использовать 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 }
источник
Если вы не хотите заранее преобразовывать всю карту в массив и / или деструктурировать массивы ключ-значение, вы можете использовать эту глупую функцию:
/** * 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)
Зависит от вашего религиозного рвения в том, чтобы избегать редактирования прототипов, но я считаю, что это позволяет мне сохранять интуитивно понятный вид.
источник
Вы можете использовать массивы map (), но для Maps такой операции нет. Решение от доктора Акселя Раушмайера :
Пример:
let map0 = new Map([ [1, "a"], [2, "b"], [3, "c"] ]); const map1 = new Map( [...map0] .map(([k, v]) => [k * 2, '_' + v]) );
привело к
{2 => '_a', 4 => '_b', 6 => '_c'}
источник
Может так:
const m = new Map([["a", 1], ["b", 2], ["c", 3]]); m.map((k, v) => [k, v * 2]); // Map { 'a' => 2, 'b' => 4, 'c' => 6 }
Раньше вам нужно было только патч обезьяны
Map
:Map.prototype.map = function(func){ return new Map(Array.from(this, ([k, v]) => func(k, v))); }
Мы могли бы написать более простую форму этого патча:
Map.prototype.map = function(func){ return new Map(Array.from(this, func)); }
Но мы бы тогда заставили нас написать,
m.map(([k, v]) => [k, v * 2]);
что мне кажется более болезненным и уродливым.Только значения сопоставления
Мы также можем отображать только значения, но я бы не советовал использовать это решение, поскольку оно слишком конкретное. Тем не менее это можно сделать, и у нас будет следующий API:
const m = new Map([["a", 1], ["b", 2], ["c", 3]]); m.map(v => v * 2); // Map { 'a' => 2, 'b' => 4, 'c' => 6 }
Как и перед патчем таким образом:
Map.prototype.map = function(func){ return new Map(Array.from(this, ([k, v]) => [k, func(v)])); }
Может быть, вы можете иметь и то, и другое, назвав вторую,
mapValues
чтобы было ясно, что вы на самом деле не отображаете объект, как это, вероятно, ожидалось.источник