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

JavaScript 객체 배열에서 동일한 이름별로 숫자 값 합산하기

문제 상황

다음과 같이 사람 이름(firstName)과 숫자(value)를 담은 객체 배열이 있다고 가정해 보겠습니다.

const arr = [
    {"firstName":"John", "value": 89},
    {"firstName":"Peter", "value": 151},
    {"firstName":"Anna", "value": 200},
    {"firstName":"Peter", "value": 22},
    {"firstName":"Anna","value": 60}
];

여기서 작성해야 할 것은 firstName 속성의 값이 서로 같은 객체들을 하나로 묶고, 그들의 value 속성을 모두 더하는 자바스크립트 함수입니다.

따라서 위 배열에 이 함수를 적용하면 다음과 같은 결과가 나와야 합니다.

const output = [
    {"firstName":"John", "value": 89},
    {"firstName":"Peter", "value": 173},
    {"firstName":"Anna", "value": 260}
];

해결 아이디어

배열을 처음부터 끝까지 순회하면서 각 객체와 firstName 값이 같은 객체를 찾습니다. 이 문맥에서 '유사한 객체'란 firstName 값이 동일한 객체를 의미합니다.

같은 이름을 가진 객체를 발견하면 그중 한곳에 value를 누적하고, 결과 배열에는 이름당 하나의 객체만 유지하면 됩니다. 이 과정을 배열의 끝까지 반복하면 원하는 형태의 배열을 얻을 수 있습니다.

예제 코드

다음은 위 아이디어를 구현한 코드입니다.

const arr = [
    {"firstName":"John", "value": 89},
    {"firstName":"Peter", "value": 151},
    {"firstName":"Anna", "value": 200},
    {"firstName":"Peter", "value": 22},
    {"firstName":"Anna","value": 60}
];
const sumSimilar = arr => {
    const res = [];
    for(let i = 0; i < arr.length; i++){
        const ind = res.findIndex(el => el.firstName === arr[i].firstName);
        if(ind === -1){
            res.push(arr[i]);
        }else{
            res[ind].value += arr[i].value;
        };
    };
    return res;
};
console.log(sumSimilar(arr));

코드의 핵심은 findIndex()입니다. 결과 배열(res) 안에 현재 객체와 같은 firstName을 가진 요소가 이미 존재하는지 확인하고, 없으면(-1) 새로 추가하고, 있으면 해당 위치의 value에 현재 값을 더해 줍니다.

출력 결과

위 코드를 실행하면 콘솔에 다음과 같이 출력됩니다.

[
    { firstName: 'John', value: 89 },
    { firstName: 'Peter', value: 173 },
    { firstName: 'Anna', value: 260 }
]

참고: reduce()를 활용한 대안

배열 메서드 reduce()를 사용하면 좀 더 선언적인 방식으로 같은 결과를 얻을 수 있습니다.

const sumSimilar = arr =>
   Object.values(
      arr.reduce((acc, {firstName, value}) => {
         acc[firstName] = acc[firstName] || { firstName, value: 0 };
         acc[firstName].value += value;
         return acc;
      }, {})
   );

findIndex를 사용하는 첫 번째 방식은 데이터가 많아질수록 성능이 떨어질 수 있습니다(O(n²)). 반면 객체나 Map을 해시 맵처럼 활용하는 reduce 방식은 선형 시간(O(n))에 처리되므로, 대량의 데이터를 다룰 때는 후자가 더 효율적입니다.