다음과 같은 JSON 객체 배열이 있다고 가정해 보겠습니다.
const arr = [
{
"id": "03868185",
"month_10": 6,
},
{
"id": "03870584",
"month_6": 2,
},
{
"id": "03870584",
"month_7": 5,
},
{
"id": "51295",
"month_1": 1,
},
{
"id": "51295",
"month_10": 1,
},
{
"id": "55468",
"month_11": 1,
}
];배열을 자세히 살펴보면 일부 객체들이 동일한 "id" 속성 값을 공유하고 있는 것을 확인할 수 있습니다. 예를 들어 "03870584"라는 id를 가진 객체가 두 개 있고, "51295" 역시 마찬가지입니다.
이번 글의 목표는 특정 id에 해당하는 모든 키/값 쌍을 하나의 객체로 묶어주는 JavaScript 함수를 작성하는 것입니다. 즉, 같은 id를 가진 여러 개의 객체를 하나로 병합해야 합니다.
접근 방식
해결 방법의 핵심 아이디어는 다음과 같습니다.
- 결과 배열과 함께, 각 id가 결과 배열의 어느 위치(인덱스)에 있는지 추적하는 해시 맵을 사용합니다.
- 배열을 순회하면서 현재 객체의 id가 이미 맵에 등록되어 있다면, 해당 인덱스의 기존 객체에 나머지 키/값 쌍을 추가합니다.
- 아직 등록되지 않은 id라면 객체를 결과 배열에 새로 추가하고, 그 위치를 맵에 기록합니다.
예제 코드
이를 구현한 코드는 다음과 같습니다.
const arr = [
{
"id": "03868185",
"month_10": 6,
},
{
"id": "03870584",
"month_6": 2,
},
{
"id": "03870584",
"month_7": 5,
},
{
"id": "51295",
"month_1": 1,
},
{
"id": "51295",
"month_10": 1,
},
{
"id": "55468",
"month_11": 1,
}
];
const groupById = (arr = []) => {
const map = {};
const res = [];
arr.forEach(el => {
if(map.hasOwnProperty(el['id'])){
const index = map[el['id']] - 1;
const key = Object.keys(el)[1];
res[index][key] = el[key];
}
else{
map[el['id']] = res.push(el);
}
})
return res;
};
console.log(groupById(arr));코드 동작 원리
map객체는 각 id가 결과 배열res의 몇 번째 요소인지 저장하는 역할을 합니다.res.push(el)은 요소를 추가한 뒤 배열의 새로운 길이를 반환합니다. 따라서 여기서 1을 빼면 실제 인덱스를 얻을 수 있습니다.Object.keys(el)[1]은 객체에서id를 제외한 두 번째 키(예:month_10,month_7)를 가져오는 데 사용됩니다.- id가 처음 등장하면
else블록이 실행되어 객체가 결과 배열에 추가되고, 그 위치가 맵에 기록됩니다.
출력 결과
콘솔에 출력되는 결과는 다음과 같습니다.
[
{ id: '03868185', month_10: 6 },
{ id: '03870584', month_6: 2, month_7: 5 },
{ id: '51295', month_1: 1, month_10: 1 },
{ id: '55468', month_11: 1 }
]실행 결과를 보면 동일한 id를 가졌던 객체들이 성공적으로 하나로 병합된 것을 확인할 수 있습니다. 이 접근 방식은 배열을 단 한 번만 순회하므로 시간 복잡도가 O(n)으로 매우 효율적이며, 대용량 데이터를 처리할 때도 안정적으로 동작합니다.