다음과 같이 여러 개의 객체를 담고 있는 배열이 있다고 가정해 보겠습니다.
const arr = [
{_id : "1", S : "2"},
{_id : "1", M : "4"},
{_id : "2", M : "1"},
{_id : "6" , M : "1"},
{_id : "3", S : "3"}
];우리가 작성해야 할 함수는 이러한 배열을 입력받아 '_id' 키의 값이 서로 같은 객체들을 하나로 묶어주는 역할을 합니다. 단순히 묶기만 하는 것이 아니라, 각 그룹 내에서 '_id'를 제외한 나머지 속성(M, S)의 값들은 모두 합산해야 하며, 그 총합을 담은 total 속성도 함께 만들어 주어야 합니다.
따라서 최종적으로 얻어야 하는 결과는 다음과 같은 형태입니다.
const output = [
{_id : "1", M : 4, S : 2, total: 6},
{_id : "2", M : 1, S : 0, total: 1},
{_id : "6", M : 1, S : 0, total: 1},
{_id : "3", M : 0, S : 3, total: 3}
];구현 예제
이를 구현한 전체 코드는 다음과 같습니다.
const arr = [
{_id : "1", S : "2"},
{_id : "1", M : "4"},
{_id : "2", M : "1"},
{_id : "6" , M : "1"},
{_id : "3", S : "3"}
];
const pickAllConstraints = arr => {
let constraints = [];
arr.forEach(el => {
const keys = Object.keys(el);
constraints = [...constraints, ...keys];
});
return constraints.filter((el, ind) => el !== '_id' && ind === constraints.lastIndexOf(el));
};
const buildItem = (cons, el = {}, prev = {}) => {
const item = {};
let total = 0
cons.forEach(i => {
item[i] = (+el[i] || 0) + (+prev[i] || 0);
total += item[i];
});
item.total = total;
return item;
}
const buildCumulativeArray = arr => {
const constraints = pickAllConstraints(arr);
const map = {}, res = [];
arr.forEach(el => {
const { _id } = el;
if(map.hasOwnProperty(_id)){
res[map[_id] - 1] = {
_id, ...buildItem(constraints, el, res[map[_id] - 1])
};
}else{
map[_id] = res.push({
_id, ...buildItem(constraints, el)
});
}
});
return res;
};
console.log(buildCumulativeArray(arr));실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
[
{ _id: '1', M: 4, S: 2, total: 6 },
{ _id: '2', M: 1, S: 0, total: 1 },
{ _id: '6', M: 1, S: 0, total: 1 },
{ _id: '3', M: 0, S: 3, total: 3 }
]코드 동작 원리
이 코드는 세 개의 함수로 구성되어 있으며, 각각 다음과 같은 역할을 담당합니다.
1. pickAllConstraints – 집계 대상 키 추출
배열의 모든 객체에서 키 이름을 수집한 뒤 중복을 제거하고, '_id'는 제외합니다. 이 예제에서는 ['M', 'S']라는 목록이 만들어집니다. 키를 미리 추출해 두면 어떤 속성 조합이 들어오더라도 유연하게 대응할 수 있다는 장점이 있습니다.
2. buildItem – 값 누적 처리
현재 객체(el)와 이전까지 누적된 객체(prev)를 받아 각 키별로 값을 더합니다. (+el[i] || 0) 패턴을 사용하면 해당 키가 존재하지 않거나 값이 문자열이더라도 안전하게 숫자 0으로 처리할 수 있습니다. 마지막에는 모든 키 값을 합산한 total을 계산해 함께 반환합니다.
3. buildCumulativeArray – 그룹화 및 병합
map 객체에 각 _id가 처음 등장했을 때의 인덱스를 기록해 둡니다. 같은 _id를 가진 객체가 다시 나타나면 새 항목을 추가하는 대신, 기존 항목 위에 buildItem의 누적 결과를 덮어써서 하나의 객체로 병합합니다. 이 과정을 거치면 _id별로 속성 값이 합산된 최종 배열이 완성됩니다.
참고로 입력 데이터에서 속성 값이 문자열("4") 형태로 되어 있어도 + 연산자를 통해 숫자로 변환되기 때문에, 실행 결과의 값들은 숫자(4, 2, 6 등)로 출력됩니다.