문제 상황
어떤 회사의 제품 정보가 담긴 두 개의 객체 배열이 있다고 가정해 보겠습니다.
const first = [
{
id: "57e7a1cd6a3f3669dc03db58",
quantity:3
},
{
id: "57e77b06e0566d496b51fed5",
quantity:3
},
{
id: "57e7a1cd6a3f3669dc03db58",
quantity:3
},
{
id: "57e77b06e0566d496b51fed5",
quantity:3
}
];
const second = [
{
id: "57e7a1cd6a3f3669dc03db58",
quantity:6
},
{
id: "57e77b06e0566d496b51fed5",
quantity:6
}
];여기서 요구되는 작업은 다음과 같습니다.
- 두 배열을 하나로 병합합니다.
- 동일한
id를 가진 객체가 중복으로 나타나지 않도록 합니다. id가 중복되는 객체들의quantity속성 값은 서로 합산합니다.
해결 방법: reduce()를 활용한 병합 함수
이러한 요구 사항을 충족하려면 reduce() 메서드를 활용하면 효과적입니다. 스프레드 연산자(...)로 두 배열을 먼저 하나로 펼친 뒤, 각 객체의 id가 누적 배열에 이미 존재하는지 확인하고, 존재하면 quantity를 더하고 존재하지 않으면 새 객체로 추가하는 방식입니다.
예제 코드
const first = [
{
id: "57e7a1cd6a3f3669dc03db58",
quantity:3
},
{
id: "57e77b06e0566d496b51fed5",
quantity:3
},
{
id: "57e7a1cd6a3f3669dc03db58",
quantity:3
},
{
id: "57e77b06e0566d496b51fed5",
quantity:3
}
];
const second = [
{
id: "57e7a1cd6a3f3669dc03db58",
quantity:6
},
{
id: "57e77b06e0566d496b51fed5",
quantity:6
}
];
const mergeArray = (first, second) => {
return [...first, ...second].reduce((acc, val, i, arr) => {
const { id, quantity } = val;
const ind = acc.findIndex(el => el.id === id);
if(ind !== -1){
acc[ind].quantity += quantity;
}else{
acc.push({
id,
quantity
});
}
return acc;
}, []);
}
console.log(mergeArray(first, second));코드 설명
[...first, ...second] 구문은 두 배열의 모든 요소를 순서대로 하나의 새로운 배열로 결합합니다. 이후 reduce()가 각 객체를 순회하면서 다음 작업을 수행합니다.
- 현재 객체에서
id와quantity를 추출합니다. findIndex()로 누적 배열(acc) 안에 같은id를 가진 객체가 있는지 확인합니다.- 존재한다면 해당 객체의
quantity에 현재 값을 더하고, 없다면 새로운 객체를 배열에 추가합니다. - 모든 순회가 끝나면 중복 없이 수량이 합산된 최종 배열을 반환합니다.
실행 결과
위 코드를 실행하면 콘솔에 아래와 같은 결과가 출력됩니다.
[
{ id: '57e7a1cd6a3f3669dc03db58', quantity: 12 },
{ id: '57e77b06e0566d496b51fed5', quantity: 12 }
]결과에서 확인할 수 있듯이, 각 id별로 중복된 객체들이 하나로 병합되었으며, 수량 역시 정확하게 합산되었습니다(예: 3 + 3 + 6 = 12).
마무리
이 방식은 장바구니 항목 통합, 재고 데이터 집계 등 실무에서 자주 마주치는 시나리오에 유용하게 적용할 수 있습니다. 참고로 데이터 양이 매우 큰 경우에는 findIndex()의 반복 검색으로 인한 O(n²) 성능 저하를 피하기 위해 Map> 객체를 사용해 id를 키로 관리하는 방식(O(n))을 고려하는 것도 좋습니다.