실무에서는 다음과 같이 동일한 데이터가 여러 번 중복되어 포함된 객체 배열을 자주 다루게 됩니다.
const arr = [{
"value": 10,
"id": "111",
"name": "BlackCat",
}, {
"value": 10,
"id": "111",
"name": "BlackCat",
}, {
"value": 15,
"id": "777",
"name": "WhiteCat",
}];이 배열을 인자로 받아, "id" 속성의 값이 서로 같은 객체들을 하나로 병합하는 JavaScript 함수를 작성해야 합니다. 병합할 때는 해당 id가 몇 번 등장했는지를 나타내는 count 속성도 함께 추가합니다.
따라서 위 배열에 함수를 적용하면 결과는 다음과 같아야 합니다.
const output = [{
"value": 10,
"id": "111",
"name": "BlackCat",
"count": 2,
}, {
"value": 15,
"id": "777",
"name": "WhiteCat",
"count": 1,
}]구현 예제
const arr = [{
"value": 10,
"id": "111",
"name": "BlackCat",
}, {
"value": 10,
"id": "111",
"name": "BlackCat",
}, {
"value": 15,
"id": "777",
"name": "WhiteCat",
}];
const combinedItems = (arr = []) => {
const res = arr.reduce((acc, obj) => {
let found = false;
for (let i = 0; i < acc.length; i++) {
if (acc[i].id === obj.id) {
found = true;
acc[i].count++;
};
}
if (!found) {
obj.count = 1;
acc.push(obj);
}
return acc;
}, []);
return res;
}
console.log(combinedItems(arr));코드 설명
reduce()메서드를 사용해 배열을 순회하면서 결과를 담을 누적 배열acc를 만듭니다.- 각 객체에 대해 누적 배열 안에 같은
id를 가진 항목이 이미 존재하는지 확인합니다. - 같은 id가 존재하면
found플래그를 true로 바꾸고 해당 항목의count를 1 증가시킵니다. - 같은 id가 없다면 새 객체의
count를 1로 초기화한 뒤 누적 배열에 추가합니다.
출력 결과
콘솔에 출력되는 결과는 다음과 같습니다.
[
{ value: 10, id: '111', name: 'BlackCat', count: 2 },
{ value: 15, id: '777', name: 'WhiteCat', count: 1 }
]참고: 성능 개선 팁
위 방식은 매번 내부 반복문으로 기존 항목을 검색하기 때문에 시간 복잡도가 O(n²)입니다. 데이터 양이 많다면 Map 객체를 활용해 O(n)으로 최적화할 수 있습니다.
const combinedItems = (arr = []) => {
const map = new Map();
arr.forEach(obj => {
if (map.has(obj.id)) {
map.get(obj.id).count++;
} else {
map.set(obj.id, { ...obj, count: 1 });
}
});
return [...map.values()];
};Map은 키 조회가 상수 시간에 이루어지므로 대용량 데이터에서도 빠르게 동작하며, 마지막에 [...map.values()]로 배열 형태의 결과를 손쉽게 얻을 수 있습니다.