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

JavaScript 객체 배열에서 고유 키별 개수 세는 방법

문제 상황

다음과 같이 객체로 이루어진 배열이 있다고 가정해 보겠습니다.

const arr = [
  {
    assigned_user:{
      name:'Paul',
      id: 34158
    },
    doc_status: "processed"
  },
  {
    assigned_user:{
      name:'Simon',
      id: 48569
    },
    doc_status: "processed"
  },
  {
    assigned_user:{
      name:'Simon',
      id: 48569
    },
    doc_status: "processed"
  }
];

위 배열에는 'Paul'이 한 번, 'Simon'이 두 번 등장합니다. 우리가 작성해야 할 함수는 이러한 객체 배열을 입력으로 받아, assigned_user 속성에 포함된 고유한 사용자별로 등장 횟수를 집계하는 것입니다.

즉, 중복되지 않는 각 사용자 이름을 키로 삼고, 해당 사용자가 배열에 몇 번 나타나는지를 값으로 갖는 결과를 만들어 반환해야 합니다.

reduce()를 활용한 해결 방법

가장 일반적인 접근 방식은 배열 메서드인 reduce()를 사용하는 것입니다. 빈 객체를 초기값으로 설정한 뒤, 배열을 순회하면서 각 사용자 이름을 키로 사용해 카운트를 누적하면 됩니다.

const countUnique = (arr = []) => {
  let res = [];
  res = arr.reduce(function (r, o) {
    let user = o.assigned_user.name;
    (r[user]) ? ++r[user] : r[user] = 1;
    return r;
  }, {}),
  result = Object.keys(res).map(function (k) {
    return {user: k, count: res[k]};
  });
  return res;
}
console.log(countUnique(arr));

코드 동작 원리

reduce()는 배열의 각 요소를 순회하며 누적값(r)을 업데이트합니다. 현재 객체의 assigned_user.name 값을 추출한 후, 해당 키가 누적 객체에 이미 존재하면 카운트를 1 증가시키고(++r[user]), 존재하지 않으면 1로 초기화합니다(r[user] = 1). 모든 요소를 처리하면 사용자별 개수가 담긴 객체가 완성됩니다.

실행 결과

콘솔에 출력되는 결과는 다음과 같습니다.

{ Paul: 1, Simon: 2 }

'Paul'은 한 번, 'Simon'은 두 번 등장했으므로 정확하게 집계된 것을 확인할 수 있습니다.

참고: 결과를 배열 형태로 얻기

위 코드의 result 변수처럼 Object.keys()map()을 조합하면, 단순 객체 대신 다음과 같은 객체 배열 형태로도 결과를 얻을 수 있습니다.

[
  { user: 'Paul', count: 1 },
  { user: 'Simon', count: 2 }
]

반환값만 res 대신 result로 바꾸면 되므로, 용도에 맞게 선택하여 사용하면 됩니다.

Map을 활용한 현대적인 대안

ES6 이상 환경이라면 Map을 사용하는 방법도 좋습니다. 키 관리가 더 명확하고 성능 면에서도 유리합니다.

const countUnique = (arr = []) => {
  const map = new Map();
  arr.forEach(({ assigned_user }) => {
    const user = assigned_user.name;
    map.set(user, (map.get(user) || 0) + 1);
  });
  return Object.fromEntries(map);
};

console.log(countUnique(arr)); // { Paul: 1, Simon: 2 }

두 방법 모두 시간 복잡도는 O(n)으로, 배열을 한 번만 순회하면 되기 때문에 대용량 데이터에서도 효율적으로 동작합니다.