reduce로 날짜별 정보 배열 만들기
안녕하세요!
이번 글에서는 reduce
를 사용해 날짜별로 데이터를 그룹화하는 방법을 알아보려고 합니다.
개인적으로 reduce
를 자주 사용하지 않았었는데, 최근 업무에서 이 기능을 활용할 일이 생겨서 그 경험을 정리해 보았습니다.
목표
이번 작업에서는 캘린더 UI에서 날짜별로 아코디언 방식으로 데이터를 펼치는 기능을 구현해야 했습니다.
API로부터 받은 데이터는 아래와 같이 날짜별 정보를 담고 있는 리스트 형식이었는데요:
// 기본 데이터
const baseData = [
{
startedAt: "2024-10-30T10:00:00+09:00",
rooms: {
id: "1",
},
},
{
startedAt: "2024-10-30T11:00:00+09:00",
rooms: {
id: "2",
},
},
{
startedAt: "2024-10-31T10:00:00+09:00",
rooms: {
id: "3",
},
},
{
startedAt: "2024-11-01T10:00:00+09:00",
rooms: {
id: "4",
},
},
{
startedAt: "2024-11-01T11:00:00+09:00",
rooms: {
id: "5",
},
},
];
위와 같은 데이터 구조로는 UI를 구현하기 어렵다고 판단하여, 각 날짜별로 데이터를 묶어서 배열을 만들기로 했습니다.
최종 목표 데이터
const expectData = [
[
{ startedAt: "2024-10-30T10:00:00+09:00", rooms: { id: "1" } },
{ startedAt: "2024-10-30T11:00:00+09:00", rooms: { id: "2" } },
],
[{ startedAt: "2024-10-31T10:00:00+09:00", rooms: { id: "3" } }],
[
{ startedAt: "2024-11-01T10:00:00+09:00", rooms: { id: "4" } },
{ startedAt: "2024-11-01T11:00:00+09:00", rooms: { id: "5" } },
],
];
구현 코드 및 설명
바로 결과부터 보자면, 최종 코드는 다음과 같습니다:
const weeklyShifts = Object.values(
(baseData || []).reduce((acc, record) => {
const date = record?.startedAt.split("T")[0];
return {
...acc,
[date]: [...(acc?.[date] ?? []), record],
};
}, {})
);
이제 각 코드 부분을 하나씩 설명해 드리겠습니다.
1. reduce
로 배열 순회하기
reduce
는 배열에 대해 지정된 처리를 반복 수행하는 함수입니다.
map
이나 filter
와 달리, reduce
는 배열에서 원하는 형태로 데이터를 유연하게 가공할 수 있는데요,
합계를 구하거나 새로운 데이터 구조를 만드는 데 자주 사용됩니다.
기본 문법은 다음과 같습니다:
array.reduce((accumulator, currentValue, index, array) => {
// 여기서 처리
}, initialValue);
- accumulator: 이전 처리 결과가 전달되는 변수입니다. 첫 번째 순회에서는
initialValue
가 전달됩니다. 이를 생략하면 배열의 첫 번째 요소가 초기값으로 설정됩니다. - currentValue: 현재 처리 중인 배열 요소입니다.
- index: 현재 처리 중인 요소의 인덱스입니다. (생략 가능)
- array: 원본 배열입니다. (생략 가능)
이 reduce
를 사용해 baseData
배열을 순회하게 됩니다. 이해를 돕기 위해 각 요소를 console.log
로 출력해 보겠습니다:
const weeklyShifts = (baseData || []).reduce((acc, record) => {
console.log("acc", acc);
console.log("record", record);
}, {});
출력 결과:
{} // acc
{ startedAt: '2024-10-30T10:00:00+09:00', rooms: { id: '1' } } // record
초기값으로 빈 객체 {}
를 설정했기 때문에, 첫 번째 순회에서는 acc
에 빈 객체가 전달되고, record
에는 배열의 첫 번째 객체가 전달됩니다.
2. 날짜 정보 생성 및 분기 처리
이제 startedAt
에서 날짜 정보를 추출하고, 이를 기준으로 배열을 그룹화하는 로직을 추가합니다:
const weeklyShifts = (baseData || []).reduce((acc, record) => {
const date = record?.startedAt.split("T")[0];
return {
...acc,
[date]: [...(acc?.[date] ?? []), record],
};
}, {});
여기서는 record.startedAt
에서 날짜만 추출한 후, 이 날짜를 객체의 key로 사용하고, 해당 날짜에 속하는 데이터를 배열로 묶어 value에 저장합니다.
첫 번째 순회 결과는 다음과 같습니다:
{
'2024-10-30': [
{ startedAt: '2024-10-30T10:00:00+09:00', rooms: { id: '1' } }
]
}
같은 날짜가 있을 경우 해당 날짜의 배열에 데이터를 추가해 나갑니다.
두 번째 순회 결과:
{
'2024-10-30': [
{ startedAt: '2024-10-30T10:00:00+09:00', rooms: { id: '1' } },
{ startedAt: '2024-10-30T11:00:00+09:00', rooms: { id: '2' } }
]
}
세 번째 데이터는 날짜가 다르기 때문에 새로운 key와 value가 생성됩니다.
최종 결과:
{
'2024-10-30': [
{ startedAt: '2024-10-30T10:00:00+09:00', rooms: { id: '1' } },
{ startedAt: '2024-10-30T11:00:00+09:00', rooms: { id: '2' } }
],
'2024-10-31': [
{ startedAt: '2024-10-31T10:00:00+09:00', rooms: { id: '3' } }
],
'2024-11-01': [
{ startedAt: '2024-11-01T10:00:00+09:00', rooms: { id: '4' } },
{ startedAt: '2024-11-01T11:00:00+09:00', rooms: { id: '5' } }
]
}
3. Object.values
로 배열 만들기
마지막으로, 날짜별로 데이터를 배열로 묶어주기 위해 Object.values
를 사용합니다.
이 함수는 객체의 값들을 배열로 반환해 줍니다.
const weeklyShifts = Object.values(
(baseData || []).reduce((acc, record) => {
const date = record?.startedAt.split("T")[0];
return {
...acc,
[date]: [...(acc?.[date] ?? []), record],
};
}, {})
);
최종 결과는 다음과 같이 날짜별로 그룹화된 배열이 됩니다:
[
[
{ startedAt: "2024-10-30T10:00:00+09:00", rooms: { id: "1" } },
{ startedAt: "2024-10-30T11:00:00+09:00", rooms: { id: "2" } },
],
[{ startedAt: "2024-10-31T10:00:00+09:00", rooms: { id: "3" } }],
[
{ startedAt: "2024-11-01T10:00:00+09:00", rooms: { id: "4" } },
{ startedAt: "2024-11-01T11:00:00+09:00", rooms: { id: "5" } },
],
];
이렇게 해서 원하는 형태의 데이터를 얻을 수 있었습니다! 🥳
마무리
reduce
를 활용해 데이터를 변환하는 방법을 알아보았는데요, 도움이 되셨나요?
저도 이번 기회를 통해 reduce
를 더 잘 활용할 수 있게 된 것 같아서 기쁩니다! 🥳
이 글이 누군가에게 작은 도움이 되기를 바랍니다.
'Javascript' 카테고리의 다른 글
TypeScript로 클래스가 아닌 것 상속하기 (0) | 2024.11.09 |
---|---|
TypeScript의 불편함을 해결하는 @total-typescript/ts-reset 도입하기 (1) | 2024.11.09 |
실무에서 바로 쓸 수 있는 TypeScript 타입 8선 (1) | 2024.11.09 |
자바스크립트 얕은 복사 vs 깊은 복사, 완벽 정리! (0) | 2024.10.30 |
Next.js 15, 달라진 점 싹 다 훑어보기! (1) | 2024.10.30 |