실무에서는 사용자별 활동 데이터를 날짜 단위로 재구성해야 하는 경우가 자주 있습니다. 이번 글에서는 여러 사용자의 월별 데이터를 날짜 기준으로 그룹화하는 JavaScript 함수를 만들어 보겠습니다.
문제 상황
다음과 같이 사용자 이름을 키로 하고, 각 사용자마다 '연도-월' 형식의 날짜와 값이 담긴 객체가 있다고 가정해 봅시다.
const obj = {
"Mary": {
"2016-1": 2,
"2016-5": 1,
"2016-3": 1
},
"Paul": {
"2016-1": 1,
"2016-3": 1
},
"moth": {
"2016-1": 2,
"2016-5": 1
}
};여기서 우리가 원하는 결과는 사용자 중심 구조를 날짜 중심 구조로 뒤집는 것입니다. 즉, 각 고유한 날짜가 하나의 객체가 되고, 그 안에 해당 날짜에 데이터가 있는 사용자 목록(names)과 값 목록(values)이 함께 담기도록 변환해야 합니다.
해결 방법: groupByDate 함수
핵심 로직은 다음과 같습니다.
Object.keys()로 모든 사용자 이름을 추출합니다.- 각 사용자의 날짜 키를 순회하면서 결과 객체(res)에 해당 날짜가 존재하는지 확인합니다.
- 날짜가 없으면 새로운 항목을 생성하고, 이미 존재하면 names 배열과 values 배열에 각각 추가(push)합니다.
const obj = {
"Mary": {
"2016-1": 2,
"2016-5": 1,
"2016-3": 1
},
"Paul": {
"2016-1": 1,
"2016-3": 1
},
"moth": {
"2016-1": 2,
"2016-5": 1
}
};
const groupByDate = (obj = {}) => {
const names = Object.keys(obj);
const res = {};
for(let i = 0; i < names.length; i++){
const name = names[i];
const dates = Object.keys(obj[name]);
for(let j = 0; j < dates.length; j++){
const date = dates[j];
if(!res.hasOwnProperty(date)){
res[date] = {
names: [name],
values: [obj[name][date]]
}
}
else{
res[date].names.push(name);
res[date].values.push(obj[name][date]);
};
};
};
return res;
};
console.log(groupByDate(obj));실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
{
'2016-1': { names: [ 'Mary', 'Paul', 'moth' ], values: [ 2, 1, 2 ] },
'2016-5': { names: [ 'Mary', 'moth' ], values: [ 1, 1 ] },
'2016-3': { names: [ 'Mary', 'Paul' ], values: [ 1, 1 ] }
}코드 설명 및 참고 사항
- 시간 복잡도: 사용자 수를 n, 각 사용자의 날짜 수를 m이라 하면 전체 O(n × m)으로 처리되므로 매우 효율적입니다.
- hasOwnProperty 활용:
res.hasOwnProperty(date)를 사용하면 프로토타입 체인의 속성과 충돌 없이 객체에 해당 키가 직접 존재하는지 정확히 확인할 수 있습니다. - 대체 문법: 최신 JavaScript에서는
Object.prototype.hasOwnProperty.call(res, date)또는date in res,Object.hasOwn(res, date)(ES2022)를 사용할 수도 있습니다. - 확장성: 이 패턴은 월별 통계 집계, 차트용 데이터 변환, 로그 분석 등 다양한 상황에서 응용할 수 있습니다.
이처럼 객체의 키 구조를 반전시키는 그룹화 기법은 데이터 시각화나 리포트 작성 시 특정 기간별로 데이터를 묶어야 할 때 매우 유용하게 활용됩니다.