Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

JavaScript에서 key 속성을 기준으로 객체 그룹화하는 방법

문제 상황 이해하기

JavaScript 개발을 하다 보면 중첩된 배열 안의 객체들을 특정 키(key) 값 기준으로 묶어야 하는 경우가 자주 발생합니다. 이번 글에서는 다음과 같은 데이터 구조를 다뤄보겠습니다.

하나의 부모 배열(parentArray) 안에 크기가 같은 여러 개의 하위 배열(sub array)이 들어 있습니다. 각 하위 배열은 keyvalue라는 두 가지 속성을 가진 객체들로 구성되어 있으며, 다음과 같은 조건이 성립합니다.

  • 같은 하위 배열 내에서는 두 객체가 동일한 키를 가질 수 없습니다.
  • 모든 하위 배열은 서로 같은 n개의 키 집합(n은 하위 배열의 크기)을 공유합니다.

목표

최종적으로 만들고자 하는 결과물은 객체의 key 값을 기준으로, 해당 키에 대응하는 모든 value들을 하나의 배열에 담은 객체입니다.

예시 데이터 살펴보기

아래는 국가 코드와 국가명이 담긴 샘플 부모 배열입니다.

const parentArray = [[
{
    key: 123,
    value: 'India'
}, {
    key: 124,
    value: 'USA'
}, {
    key: 125,
    value: 'Japan'
}, {
    key: 126,
    value: 'Denmark'
}, {
    key: 127,
    value: 'Austria'
},
], [
{
    key: 124,
    value: 'Kenya'
}, {
    key: 126,
    value: 'UK'
}, {
    key: 123,
    value: 'Germany'
}, {
    key: 127,
    value: 'Spain'
}, {
    key: 125,
    value: 'Portugal'
},
]];

두 번째 하위 배열은 첫 번째와 키 집합(123~127)은 동일하지만, 요소의 순서가 뒤섞여 있다는 점에 주목하세요. 실무에서도 API 응답처럼 순서가 보장되지 않는 데이터를 자주 접하게 됩니다.

해결 접근 방식

핵심 아이디어는 단순합니다.

  1. 부모 배열을 순회하면서 각 하위 배열에 차례대로 접근합니다.
  2. 하위 배열의 각 객체에서 keyvalue를 추출합니다.
  3. 해당 키가 결과 객체(map)에 이미 존재하면 기존 배열에 값을 추가(push)하고,
  4. 존재하지 않으면 새로운 배열을 생성해 값을 넣습니다.

전체 구현 코드

위 로직을 forEach

const parentArray = [[
{
    key: 123,
    value: 'India'
}, {
    key: 124,
    value: 'USA'
}, {
    key: 125,
    value: 'Japan'
}, {
    key: 126,
    value: 'Denmark'
}, {
    key: 127,
    value: 'Austria'
},
], [
{
    key: 124,
    value: 'Kenya'
}, {
    key: 126,
    value: 'UK'
}, {
    key: 123,
    value: 'Germany'
}, {
    key: 127,
    value: 'Spain'
}, {
    key: 125,
    value: 'Portugal'
},
]];

const map = {};
parentArray.forEach(arr => {
    arr.forEach(obj => {
        const { key, value } = obj;
        if(map[key]){
            map[key].push(value);
        }else{
            map[key] = [value]
        }
    })
});
console.log(map);

코드 포인트 정리

  • 구조 분해 할당: const { key, value } = obj;로 객체에서 필요한 속성만 깔끔하게 꺼냅니다.
  • 키 존재 여부 확인: if(map[key]) 조건으로 새 배열 생성과 기존 배열 추가를 한 번에 처리합니다.

실행 결과

콘솔에 출력되는 최종 결과는 다음과 같습니다.

{
    '123': [ 'India', 'Germany' ],
    '124': [ 'USA', 'Kenya' ],
    '125': [ 'Japan', 'Portugal' ],
    '126': [ 'Denmark', 'UK' ],
    '127': [ 'Austria', 'Spain' ]
}

각 키별로 두 하위 배열에 흩어져 있던 값들이 하나의 배열로 깔끔하게 그룹화된 것을 확인할 수 있습니다.

마치며

이 패턴은 단순하지만 활용 범위가 매우 넓습니다. 참고로 ES2019부터 도입된 Object.groupBy()(또는 Map을 반환하는 Map.groupBy())를 사용하면 유사한 작업을 더 선언적으로 처리할 수도 있습니다. 다만 위와 같은 직접 구현 방식은 어떤 환경에서든 동작한다는 장점이 있으므로, 로직 자체를 이해해 두면 다양한 상황에서 응용할 수 있습니다.