하나의 배열을 조건에 따라 여러 개의 배열로 나누고 싶은 경우, groupBy 메소드를 사용하면 손쉽게 그룹을 나눌 수 있다.
groupBy는 2024년 6월 26일부터 ECMAScript2024(ES15)에 정식으로 채택되었으며, IE를 제외한 최신 웹 브라우저에서 지원한다.
groupBy 메소드는 Object, Map 객체를 통해 호출이 가능하며, 각각 그룹화된 Object와 Map을 반환한다.
실행 예시는 다음과 같다.
const arr = [1, 2, 3, 4, 5];
// 1. 배열을 조건에 따라 Object 형태로 그룹핑
const groupObj = Object.groupBy(arr, (num, i) => {
return num % 2 ? 'odd' : 'even';
});
console.log(groupObj); // { odd: [1, 3, 5], even: [2, 4] }
// 2. 배열을 조건에 따라 Map 형태로 그룹핑
const groupMap = Map.groupBy(arr, (num, i) => {
return num % 2 ? 'odd' : 'even';
})
console.log(groupMap); // { 'odd' => [1, 3, 5], 'even' => [2, 4] }
첫 번째 인자로 그룹핑할 배열(혹은 반복 가능한 객체), 두 번째 인자로 그룹 key를 리턴하는 콜백 함수를 넘기면 된다.
Object.groupBy(items, callbackFn);
// 혹은
Map.groupBy(items, callbackFn);
- items: iterable한 객체(array, string, { key: value } 형태의 object
- callbackFn: <T>(element: T, index) => string 형태의 함수
실제 개발 예시
실제 프론트엔드 개발에서는 어떤 식으로 사용하게 될까?
필자의 경우는 API에서 내려받은 상품 목록을 타입별 그룹으로 나눈 후, 특정 타입 순서대로 재정렬을 해주는 컨버터를 구현해야 했다.
따라서 Object.groupBy를 사용하여 아래와 같이 그룹화를 진행한 후, 구조 분해를 통해 그룹별 노출 순서를 조정했다.
const convertCornerHome = (
homeData: (SuperDealMainResponse & { error: boolean }) | undefined,
) => {
const { themeDeals = [], mainDeals = [] } = homeData || {};
const {
themeTimeDealItems = [],
themeLimitedDealItems = [],
themeRecommendedDealItems = [],
themeUrgentDealItems = [],
} = Object.groupBy(
themeDeals,
({ themeDealType }) =>
{
TIME: 'themeTimeDealItems',
LIMITED: 'themeLimitedDealItems',
RECOMMENDED: 'themeRecommendedDealItems',
URGENT: 'themeUrgentDealItems',
}[themeDealType]
);
const totalDeals = [
// 그룹별 노출 순서 재정렬
...themeRecommendedDealItems,
...themeUrgentDealItems,
...themeTimeDealItems,
...mainDeals.slice(0, 9),
...themeLimitedDealItems,
...mainDeals.slice(9),
];
return totalDeals;
};
Node.js에서의 groupBy 사용
Node.js 환경에서 groupBy() 메소드를 호출하면 아래와 같은 TypeError가 발생할 수 있다.
TypeError: Object.groupBy is not a function
groupBy 메소드는 Node.js v21.6.* 버전에서 추가되었기 때문에 해당 함수를 사용하기 위해서는 Node 버전 21.6.* 이상을 사용해야 한다.
부득이하게 버전을 올릴 수 없는 경우에는 아래와 같은 방법이 있다.
방법 1 - core-js 사용
core-js를 사용하고 있다면, 해당 패키지에서 제공하는 폴리필 함수를 사용할 수 있다.
다만, Typescript 사용시 타입 에러가 발생할 수 있다.
import "core-js/actual/array/group-by";
const arr = [1, 2, 3, 4, 5];
const groupObj = arr.groupBy((num, i) => {
return num % 2 ? 'odd' : 'even';
});
방법 2 - polyfill 함수 구현
아래 코드처럼 reduce를 사용하여 groupBy 메소드와 동일하게 동작하는 함수를 구현하는 방법도 있다.
// 1. Object.groupBy
const groupBy = <T>(arr: T[], callback: (args: T, index: number) => string) => {
return arr.reduce<Record<string, T[]>>((obj, element, index) => {
const key = callback(element, index);
obj[key] = [...(obj[key] || []), element];
return obj;
}, {});
};
Object.groupBy ??= groupBy; // polyfill 주입
// 2. Map.groupBy
const groupBy = <T>(arr: T[], callback: (args: T, index: number) => string) => {
return arr.reduce<Map<string, T[]>>((map, element, index) => {
const key = callback(element, index);
map.set(key, [...(map.get(key) || []), element]);
return map;
}, new Map());
};
Map.groupBy ??= groupBy; // polyfill 주입
참고 링크
'Language > Javascript' 카테고리의 다른 글
숫자 콤마 처리 - Intl.NumberFormat / toLocaleString 자세히 알아보기 (2) | 2024.10.21 |
---|---|
Shadow DOM이란? + Shadow DOM 활용 예시 (0) | 2024.08.06 |
Speculation Rules API - MPA에서도 빠른 페이지 전환 제공하기 (0) | 2024.06.13 |
Javascript - ECMAScript 2023(ES14)에 추가된 기능 (0) | 2023.06.05 |
Typescript - 유틸리티 타입(Utility Type) (0) | 2022.09.25 |