.map () 자바 스크립트 ES6 맵?


89

어떻게 하시겠습니까? 본능적으로 다음과 같이하고 싶습니다.

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 ,하지만 난 실행 해요 바벨 프로젝트를하지 포함 싶어 Traceur , 그것이 현재에 의존하는 것 같다가 .

또한 fitzgen / wu.js가 내 프로젝트에 어떻게 적용했는지 추출 하는 방법에 대해서도 약간의 단서 가 없습니다 .

내가 여기서 놓친 것에 대한 명확하고 간결한 설명을 좋아할 것입니다. 감사!


ES6 Map , FYI 용 문서


사용할 수 Array.from있습니까?
Ry-

@minitech 가능하게하는과 polyfill ... 그것없이이 작업을 수행 할 수있는 방법이 없다?
neezer 2015-06-27

글쎄, 당신은 mapiterables에서 사용할 자신의 함수를 작성할 수 있습니다 for of.
Ry-

매우 멍청하지만 실제로 지도를 통해지도를 작성하려는 경우 끝에지도를 받게됩니다. 그렇지 않으면 먼저 맵을 배열로 변환하고 맵을 .map ()하는 것이 아니라 배열을 통해 매핑합니다. ISO를 사용하여지도를 쉽게 매핑 할 수 있습니다. dimap (x => [... x], x => new Map (x));
Dtipson

@Ry 글쎄, 우리는 아마 우리 자신의 프로그래밍 언어를 작성할 수 있지만 왜 ..? 매우 간단하며 수십 년 동안 대부분의 프로그래밍 언어에 존재합니다.
ruX

답변:


73

그래서 .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( )세트 및지도 포함)을 사용하여 배열로 변환합니다. ...지도 , 배열로 강제 변환되면 배열의 배열로 바뀝니다 el[0] === key && el[1] === value;(기본적으로 위의 예제 맵을 미리 채운 것과 동일한 형식으로).

각 el에 대한 개체를 반환하기 전에 람다의 인수 위치에서 배열의 구조 해제를 사용하여 해당 배열 지점을 값에 할당합니다.

Babel을 사용하는 경우 프로덕션에서 Babel의 브라우저 폴리 필 ( "core-js"및 Facebook의 "regenerator"포함)을 사용해야합니다.
나는 그것이 포함되어 있다고 확신합니다 Array.from.


예, Array.from이 작업을 수행하는 데 필요한 것 같음을 알아 차 렸습니다 . 첫 번째 예제는 배열 btw를 반환하지 않습니다.
neezer 2015-06-27

@neezer 아니, 그렇지 않습니다. 예상되는 사용이 단순한 부작용 기반 반복이기 때문에 항상 평평하게 .forEach반환합니다 (ES5 이후와 동일). 그것을 사용하려면 , 당신은 말했다 통해서, 배열을 구축하고 손으로 채울 싶어 의해 반환 또는 반복자를 통해 또는 나 . 엄청나게 독특한 일을하는 것이 아니라, 순회를하는 특정한 추함을 숨기는 것뿐입니다. 그리고 네, 포함하여 그 확인 당신이 얻을 (가 또는 무엇이든) ...undefinedforEachforEachforEach.entries().keys( ).values( )Array.frombabel-core/browser.js.from
Norguard

4
내 대답을 참조하십시오 Array.from. map 함수를 매개 변수로 사용하면 매핑하고 버리기 위해 임시 배열을 만들 필요가 없습니다.
loganfsmyth 2015 년

왜 객체를 괄호로 감싸 야하는지 설명 할 수 있습니까? 나는 여전히 ES6에 익숙하지 않으며 그 부분을 이해하는 데 어려움을 겪고 있습니다. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 레이블로 해석되고 그것이 의미하는 바가 확실하지 않다고합니다
dtc

1
@dtc 예, 여러분이 작성하는 객체를 작성할 const obj = { x: 1 };때, 코드 블록을 작성할 if (...) { /* block */ }때 작성하고 , 작성하는 화살표 함수를 작성할 때 작성합니다 () => { return 1; }. 그러면 객체의 중괄호가 아닌 함수 본문인지 어떻게 알 수 있습니까? 그리고 대답은 괄호입니다. 그렇지 않으면 이름이 드물게 사용되는 기능인 코드 블록의 레이블이라고 예상하지만 a switch또는 루프에 레이블 을 지정할 수 있으므로 break;이름으로 제거 할 수 있습니다 . 따라서 누락 된 경우 레이블이있는 함수 본문과 1MDN 예제를 기반으로하는 문이 있습니다
Norguard

34

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, FYI 가 필요한 것 같습니다 .
neezer

1
@neezer 당신은 절대적으로, 긍정적으로 해야한다 생산, 페이지에 바벨 - transpiled 코드를 사용하기 위해, 바벨의 polyfill을 사용합니다. 주위 방법은 ... 손으로, 스스로 (페이스 북의 재생기 포함)하는 모든 메소드를 구현하지 않는 한,이 없습니다
Norguard

@Norguard 알겠습니다. 구성 변경 만하면됩니다. 제쳐두고, 정말로. :)
neezer

5
참고로 [...myMap].map(mapFn)임시 배열을 만든 다음 폐기합니다. 두 번째 인수로 Array.froma mapFn를 사용합니다.
loganfsmyth

2
@wZVanG 왜 안돼 Array.from(myMap.values(), val => val + 1);?
loganfsmyth

21

그냥 사용하십시오 Array.from(iterable, [mapFn]).

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

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

이 답변에 감사드립니다. 나는 항상 Map을 임시 배열로 퍼뜨리는 패턴을 사용하고있다 Array.from().
Andru

4

이 기능을 사용할 수 있습니다.

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

3

사용 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 }

3

실제로 Map배열로 변환 한 후에도 원래 키로 Array.from. 첫 번째 항목은 이고 두 번째 항목은 변형 된 배열 을 반환하여 가능합니다 .keyvalue

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됩니다.


1

지도를 확장하고 싶습니다

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

1

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


나는 이것이 요점을 놓친 것 같다. Array.map은 아무것도 변경하지 않습니다.
Aaron

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

전체 Map을 사전에 배열로 변환하거나 키-값 배열을 구조화하지 않으려면 다음과 같은 어리석은 함수를 사용할 수 있습니다.

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


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

프로토 타입 편집을 피하려는 종교적 열의에 따라 다르지만, 이것이 직관적으로 유지할 수 있도록 해줍니다.


0

map () 배열을 사용할 수 있지만 Maps에는 그러한 작업이 없습니다. Axel Rauschmayer 박사 의 솔루션 :

  • 맵을 [키, 값] 쌍의 배열로 변환합니다.
  • 배열을 매핑하거나 필터링합니다.
  • 결과를 다시지도로 변환합니다.

예:

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

0

아마도 이렇게 :

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실제로 예상대로 개체를 매핑하고 있지 않음을 분명히 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.