객체의 속성 값으로 색인 된 객체 배열을 해시 맵으로 변환


305

사용 사례

유스 케이스는 해시 맵의 키로 사용하고 오브젝트 자체로 값을 평가하고 사용하기 위해 제공된 문자열 또는 함수를 기반으로 오브젝트 배열을 해시 맵으로 변환하는 것입니다. 이것을 사용하는 일반적인 경우는 객체 배열을 객체의 해시 맵으로 변환하는 것입니다.

암호

다음은 객체 배열을 객체의 속성 값으로 색인화 한 해시 맵으로 변환하는 JavaScript의 작은 스 니펫입니다. 해시 맵의 키를 동적으로 평가하는 기능을 제공 할 수 있습니다 (런타임). 이것이 미래의 누군가를 돕기를 바랍니다.

function isFunction(func) {
    return Object.prototype.toString.call(func) === '[object Function]';
}

/**
 * This function converts an array to hash map
 * @param {String | function} key describes the key to be evaluated in each object to use as key for hashmap
 * @returns Object
 * @Example 
 *      [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap("id")
 *      Returns :- Object {123: Object, 345: Object}
 *
 *      [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap(function(obj){return obj.id+1})
 *      Returns :- Object {124: Object, 346: Object}
 */
Array.prototype.toHashMap = function(key) {
    var _hashMap = {}, getKey = isFunction(key)?key: function(_obj){return _obj[key];};
    this.forEach(function (obj){
        _hashMap[getKey(obj)] = obj;
    });
    return _hashMap;
};

여기서 요점을 찾을 수 있습니다 . 객체 배열을 HashMap으로 변환 합니다.


Object 대신 JavaScript Map을 사용할 수 있습니다. 확인 stackoverflow.com/a/54246603/5042169
Jun711

답변:


471

이것은 다음과 관련이 있습니다 Array.prototype.reduce.

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = arr.reduce(function(map, obj) {
    map[obj.key] = obj.val;
    return map;
}, {});

console.log(result);
// { foo:'bar', hello:'world' }

참고 : Array.prototype.reduce() IE9 +이므로 이전 브라우저를 지원 해야하는 경우 polyfill해야합니다.


47
result = arr.reduce((map, obj) => (map[obj.key] = obj.val, map), {});ES6 원 라이너 팬의 경우 : D
Teodor Sandu

31
@Mtz ES6 단선 팬의 경우 아래의 mateuscb 응답이 훨씬 작고 깨끗 result = new Map(arr.map(obj => [obj.key, obj.val]));합니다. 가장 중요한 것은지도가 반환되고 있음을 명확하게 보여줍니다.
Ryan Shillington

2
@RyanShillington 우리는 jmar777에 Array.prototype.reduce의해 제안 된 답변의 맥락에 있습니다 . Map실제로 더 짧지 만 다른 것입니다. 나는 원래 의도와 일치하고 있었다. 이것은 포럼이 아니라는 것을 기억하십시오. SO Q / A 구조에 대한 자세한 내용을 원할 수 있습니다.
Teodor Sandu

2
@Mtz 박람회 충분합니다.
Ryan Shillington

1
이것은 요청 된 것이 아닙니다, IMHO. 표시된 배열의 올바른 결과는 다음과 같습니다 { "foo": {key: 'foo', val: 'bar'}, "hello": {key: 'hello', val: 'world'} }.. 각 원래 요소 는 전체적으로 유지해야합니다 . 또는 Q의 데이터를 사용하여 : {"345": {id:345, name:"kumar"}, ...}. FIX : 코드 변경map[obj.key] = obj;
ToolmakerSteve

302

ES6 Map ( 꽤 잘 지원됨 )을 사용하여 다음을 시도 할 수 있습니다.

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = new Map(arr.map(i => [i.key, i.val]));

// When using TypeScript, need to specify type:
// var result = arr.map((i): [string, string] => [i.key, i.val])

// Unfortunately maps don't stringify well.  This is the contents in array form.
console.log("Result is: " + JSON.stringify([...result])); 
// Map {"foo" => "bar", "hello" => "world"}


4
또한 무언가를 빼내 려면 그냥 Map사용 result.get(keyName)하는 대신 사용해야 result[keyName]합니다. 또한 문자열이 아닌 모든 객체를 키로 사용할 수 있습니다.
Simon_Weaver

5
다른 TypeScript 버전은 다음과 같습니다. var result = new Map(arr.map(i => [i.key, i.val] as [string, string]));일부는 이해하기 쉽습니다. 메모 as [string, string]유형 캐스트가 추가되었습니다.
AlexV

Chrome v71에서이 코드를 실행할 때 여전히 배열을 얻습니다.Result is: [["foo","bar"],["hello","world"]]
Jean-François Beauchamp

PS result는 OP에서 요청한 해시가 아닙니다.
Jean-François Beauchamp

1
다른 타입 스크립트 버전 :var result = new Map<string, string>(arr.map(i => [i.key, i.val]));
Aziz Javed

39

lodash , 이것은 사용하여 수행 할 수 있습니다 keyBy를 :

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = _.keyBy(arr, o => o.key);

console.log(result);
// Object {foo: Object, hello: Object}

해시 맵이 아닙니다
Pomme De Terre

37

ES6 spread + Object.assign 사용 :

array = [{key: 'a', value: 'b', redundant: 'aaa'}, {key: 'x', value: 'y', redundant: 'zzz'}]

const hash = Object.assign({}, ...array.map(s => ({[s.key]: s.value})));

console.log(hash) // {a: b, x: y}

2
완벽, 내가 필요한 것;)
피에르

1
const hash = Object.assign({}, ...(<{}>array.map(s => ({[s.key]: s.value}))));typescript로 작업하려면이 변경을 수행해야했습니다.
ruwan800

24

스프레드 연산자 사용 :

const result = arr.reduce(
    (accumulator, target) => ({ ...accumulator, [target.key]: target.val }),
    {});

jsFiddle 의 코드 스 니펫 시연 .


7
나는이 때문에 정확하게 여기에있다! 어떻게 스프레드 연산자가 새로운 키를 할당하고 누산기를 반환하는 기존의 기존 방식을 다시 수행합니까? 매번 새 사본을 생성하므로 스프레드가 제대로 수행되지 않습니다 !
AMTourky

1
이제 반복 할 때마다 퍼집니다. 감속기에서 변이하는 것이 안전해야합니다. ```const result = arr.reduce ((accumulator, target) => {accumulator [target.key] : target.val; 리턴 누산기}, {}); ```
MTJ

17

JavaScript Object 대신 Array.prototype.reduce () 및 실제 JavaScript Map을 사용할 수 있습니다 .

let keyValueObjArray = [
  { key: 'key1', val: 'val1' },
  { key: 'key2', val: 'val2' },
  { key: 'key3', val: 'val3' }
];

let keyValueMap = keyValueObjArray.reduce((mapAccumulator, obj) => {
  // either one of the following syntax works
  // mapAccumulator[obj.key] = obj.val;
  mapAccumulator.set(obj.key, obj.val);

  return mapAccumulator;
}, new Map());

console.log(keyValueMap);
console.log(keyValueMap.size);

지도와 객체의 차이점은 무엇입니까?
이전에는 Map이 JavaScript로 구현되기 전에 유사한 구조로 인해 Object가 Map으로 사용되었습니다.
사용 사례에 따라 키를 주문해야하거나지도 크기에 액세스해야하거나지도에서 자주 추가 및 제거해야하는 경우지도가 바람직합니다.

MDN 문서 에서 인용 :
객체는 키와 값을 설정하고, 값을 검색하고, 키를 삭제하고, 키에 무언가가 저장되어 있는지 여부를 감지 할 수 있다는 점에서 맵과 유사합니다. 이 때문에 (및 내장 대안이 없기 때문에) 객체는 역사적으로지도로 사용되었습니다. 그러나 어떤 경우에는 맵 사용을 선호하는 중요한 차이점이 있습니다.

  • 객체의 키는 문자열과 심볼이지만 함수, 객체 및 기본 요소를 포함하여지도의 모든 값이 될 수 있습니다.
  • 객체에 추가 된 키가 아닌 맵의 키가 정렬됩니다. 따라서 반복 할 때 Map 객체는 삽입 순서대로 키를 반환합니다.
  • size 속성을 사용하여 Map의 크기를 쉽게 얻을 수 있지만 Object의 속성 수는 수동으로 결정해야합니다.
  • 맵은 반복 가능하므로 직접 반복 할 수있는 반면, 오브젝트를 반복하려면 키를 가져 와서 반복해야합니다.
  • 객체에는 프로토 타입이 있으므로주의하지 않으면 키와 충돌 할 수있는 기본 키가 맵에 있습니다. ES5부터는 map = Object.create (null)을 사용하여 무시할 수 있지만 거의 수행되지 않습니다.
  • 키 쌍을 자주 추가 및 제거하는 시나리오에서 맵 성능이 향상 될 수 있습니다.

1
화살표가 없습니다. 변경 (mapAccumulator, obj) {...}:(mapAccumulator, obj) => {...}
mayid

15

새로운 Object.fromEntries()방법을 사용할 수 있습니다 .

예:

const array = [
   {key: 'a', value: 'b', redundant: 'aaa'},
   {key: 'x', value: 'y', redundant: 'zzz'}
]

const hash = Object.fromEntries(
   array.map(e => [e.key, e.value])
)

console.log(hash) // {a: b, x: y}


12

es2015 버전 :

const myMap = new Map(objArray.map(obj => [ obj.key, obj.val ]));

4

이것이 내가 TypeScript에서하고있는 일입니다.이 유틸리티를 넣는 작은 유틸리티 라이브러리가 있습니다.

export const arrayToHash = (array: any[], id: string = 'id') => 
         array.reduce((obj, item) =>  (obj[item[id]] = item , obj), {})

용법:

const hash = arrayToHash([{id:1,data:'data'},{id:2,data:'data'}])

또는 'id'이외의 식별자가있는 경우

const hash = arrayToHash([{key:1,data:'data'},{key:2,data:'data'}], 'key')

객체를 키로 사용하려면 typescript를 사용하면 객체를 키로 사용할 수 없으므로 객체 대신 맵을 사용해야합니다.
Dany Dhondt

3

다른 포스터에서 설명하는 것처럼 더 좋은 방법이 있습니다. 그러나 순수한 JS와 ol'fashioned 방식을 고수하고 싶다면 여기 있습니다.

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' },
    { key: 'hello', val: 'universe' }
];

var map = {};
for (var i = 0; i < arr.length; i++) {
    var key = arr[i].key;
    var value = arr[i].val;

    if (key in map) {
        map[key].push(value);
    } else {
        map[key] = [value];
    }
}

console.log(map);

이 방법보다 reduce 방법을 사용하는 것이 좋습니다. 이 방법을 사용하고 싶습니다. 간단하고 모든 것을 쉽게 볼 수 있습니다.
산토시 예 디디

나는이 접근법을 좋아한다. 때로는 가장 간단한 코드가 최고라고 생각합니다. 요즘 사람들은 변이에 의해 꺼져 있지만, 그것이 포함되어있는 한 변이는 실제로 매우 훌륭하고 성능이 뛰어납니다.
Luis Aceituno

3

새 ES6 으로 변환하려면 다음을 수행하십시오.

var kvArray = [['key1', 'value1'], ['key2', 'value2']];
var myMap = new Map(kvArray);

왜 이런 유형의지도를 사용해야합니까? 글쎄, 그것은 당신에게 달려 있습니다. 이것 좀 봐 .


2

간단한 자바 스크립트 사용

var createMapFromList = function(objectList, property) {
    var objMap = {};
    objectList.forEach(function(obj) {
      objMap[obj[property]] = obj;
    });
    return objMap;
  };
// objectList - the array  ;  property - property as the key

3
이 예제에서는 .map (...)을 사용하지 않고 아무것도 반환하지 않습니까? 이 경우에는 각각을 제안합니다.
cuddlecheek

2

lodash:

const items = [
    { key: 'foo', value: 'bar' },
    { key: 'hello', value: 'world' }
];

const map = _.fromPairs(items.map(item => [item.key, item.value]));

console.log(map); // { foo: 'bar', hello: 'world' }

1

reduce사용법이 약간 개선되었습니다 .

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = arr.reduce((map, obj) => ({
    ...map,
    [obj.key] = obj.val
}), {});

console.log(result);
// { foo: 'bar', hello: 'world' }

다른 답변 보다 빠릅니까?
orad

@orad는 아마도 누산기를 확산시키고 매 반복마다 새로운 객체를 생성하지 않을 것입니다.
Luckylooke

1

시험

let toHashMap = (a,f) => a.reduce((a,c)=> (a[f(c)]=c,a),{});


0

다음은 객체 배열을 해시 맵으로 변환하고 객체의 속성 값으로 색인을 생성하기 위해 자바 스크립트로 만든 작은 스 니펫입니다. 해시 맵의 키를 동적으로 평가하는 기능을 제공 할 수 있습니다 (런타임).

function isFunction(func){
    return Object.prototype.toString.call(func) === '[object Function]';
}

/**
 * This function converts an array to hash map
 * @param {String | function} key describes the key to be evaluated in each object to use as key for hasmap
 * @returns Object
 * @Example 
 *      [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap("id")
        Returns :- Object {123: Object, 345: Object}

        [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap(function(obj){return obj.id+1})
        Returns :- Object {124: Object, 346: Object}
 */
Array.prototype.toHashMap = function(key){
    var _hashMap = {}, getKey = isFunction(key)?key: function(_obj){return _obj[key];};
    this.forEach(function (obj){
        _hashMap[getKey(obj)] = obj;
    });
    return _hashMap;
};

여기서 요점을 찾을 수 있습니다 : https://gist.github.com/naveen-ithappu/c7cd5026f6002131c1fa


11
제발, 확장을 권장하지 마십시오 Array.prototype!
jmar777

아 알 겠어. 나는 처음에이 제안 답 : 알았는데
jmar777
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.