자바스크립트의 groupBy() API 사용법
데이터를 특정 기준에 따라 분류하는 것은 자바스크립트로 데이터 처리를 할 때 자주 필요한 작업인데요.
그런데 아직도 데이터 그룹화를 위해서 reduce()
함수나 Lodash 라이브러리를 사용하시나요?
이번 포스팅에서는 자바스크립트에서 데이터를 그룹화를 위해 쓸 수 있는 비교적 새로운 API인 groupBy()
에 대해서 알아보도록 하겠습니다.
기존 데이터 그룹화 방법
우선 예전에 자바스크립트에서 데이터 그룹화가 얼마나 불편했는지 살펴볼까요?
다음과 같이 여러 사용자의 이름, 나이, 국가를 담은 배열이 주어졌을 때,
const users = [
{ name: "John", age: 25, country: "US" },
{ name: "Jane", age: 30, country: "KR" },
{ name: "Robin", age: 22, country: "CA" },
{ name: "Doe", age: 13, country: "US" },
{ name: "Smith", age: 20, country: "KR" },
];
아래와 같이 국가를 기준으로 사용자를 분류하고 싶다고 가정해봅시다.
{
US: [
{ name: "John", age: 25, country: "US" },
{ name: "Doe", age: 13, country: "US" }
],
KR: [
{ name: "Jane", age: 30, country: "KR" },
{ name: "Smith", age: 20, country: "KR" }
],
CA: [
{ name: "Robin", age: 22, country: "CA" }
],
}
지금까지도 가장 많이 쓰이던 방법은 배열의 reduce()
함수를 사용하는 것입니다.
const usersByCountry = users.reduce((users, user) => {
const country = user.country;
if (!(country in users)) {
users[country] = [];
}
users[country].push(user);
return users;
}, {});
console.log(usersByCountry);
하지만 이 코드는 딱 봐도 그닥 직관적이지가 않습니다. 코드의 가독성이 떨어진다는 큰 단점이 있습니다.
자바스크립트 배열의 reduce() 함수를 사용하는 방법에 대해서는 별도 포스팅에서 자세히 다루고 있으니 참고하세요.
이러한 단점을 극복하기 위해서 Lodash라는 라이브러리가 많이 사용했는데요.
우선 npm이나 Bun을 사용해서 패키지를 설치해야합니다.
$ npm add lodash
$ bun add lodash
그 다음 Lodash 라이브러리의 groupBy()
라는 함수를 호출하는데, 첫 번째 인자로 분류할 배열을 넘기고, 두 번째 인자로 분류 기준이 될 속성명을 넘기면 됩니다.
import _ from "lodash";
const usersByCountry = _.groupBy(users, "country");
console.log(usersByCountry);
하지만 라이브러리를 쓰면 그 나름대로 유지보수 비용이 증가하고, 외부 패키지를 사용할 수 없는 환경도 있어서 근본적인 해결책은 되지 않았습니다.
groupBy() 기본 사용
외부 라이브러리 없이도 간단한 문법으로 데이터를 그룹화할 수 있도록 자바스크립트의 Object
와 Map
클래스에는 groupBy()
라는 정적 메서드가 추가되었습니다.
Object.groupBy()
는 첫 번째 인자로 배열, 두 번째 인자로 분류 기준이 될 콜백 함수를 받습니다.
위에서 사용한 동일한 배열로 같이 실습을 해볼께요.
const users = [
{ name: "John", age: 25, country: "US" },
{ name: "Jane", age: 30, country: "KR" },
{ name: "Robin", age: 22, country: "CA" },
{ name: "Doe", age: 13, country: "US" },
{ name: "Smith", age: 20, country: "KR" },
];
국가 속성을 기준으로 사용자를 분류해야하니, 콜백 함수에서 각 사용자의 country
속성을 읽어서 그대로 반환합니다.
const usersByCountry = Object.groupBy(users, ({ country }) => country);
console.log(usersByCountry);
그러면 다음과 같이 각 국가가 키로 해당 국적자 목록이 값으로 객체가 만들어 질 것입니다.
{
US: [
{ name: "John", age: 25, country: "US" },
{ name: "Doe", age: 13, country: "US" }
],
KR: [
{ name: "Jane", age: 30, country: "KR" },
{ name: "Smith", age: 20, country: "KR" }
],
CA: [
{ name: "Robin", age: 22, country: "CA" }
],
}
Map.groupBy()
는 Object.groupBy()
와 사용법의 거의 비슷한데 분류 결과를 객체가 아닌 맵(Map)에 담아준다는 점에서 차이가 있습니다.
맵은 객체와 달리 키로 문자열뿐 아니라 다른 자료형도 사용할 수 있어 좀 더 유연하게 그룹화를 처리할 수 있겠죠?
const usersByCountry = Map.groupBy(users, ({ country }) => country);
console.log(usersByCountry);
Map.groupBy()
를 통해 그룹화를 해보면 각 국가를 키로 해당 국적자 목록을 값으로 맵이 얻어집니다.
new Map([
[
"US",
[
{
name: "John",
age: 25,
country: "US",
},
{
name: "Doe",
age: 13,
country: "US",
},
],
],
[
"KR",
[
{
name: "Jane",
age: 30,
country: "KR",
},
{
name: "Smith",
age: 20,
country: "KR",
},
],
],
[
"CA",
[
{
name: "Robin",
age: 22,
country: "CA",
},
],
],
]);
groupBy() 고급 사용
groupBy()
API는 두 번째 인자로 콜백 함수를 받기 때문에 꼭 특정 속성의 값 뿐만 아니라 정말 다양한 기준으로 분류가 가능합니다.
예를 들어서, 25살을 기준으로 젊은이와 늙은이를 분류해보겠습니다.
const usersByAge = Object.groupBy(users, ({ age }) =>
age < 25 ? "YOUNG" : "OLD"
);
console.log(usersByAge);
{
"OLD": [
{
"name": "John",
"age": 25,
"country": "US"
},
{
"name": "Jane",
"age": 30,
"country": "KR"
}
],
"YOUNG": [
{
"name": "Robin",
"age": 22,
"country": "CA"
},
{
"name": "Doe",
"age": 13,
"country": "US"
},
{
"name": "Smith",
"age": 20,
"country": "KR"
}
]
}
이번에는 이름이 알파벳 J
로 시작하는 사람과 아닌 사람을 분류해보겠습니다.
const usersByName = Object.groupBy(users, ({ name }) => name.startsWith("J"));
console.log(usersByName);
{
"true": [
{
"name": "John",
"age": 25,
"country": "US"
},
{
"name": "Jane",
"age": 30,
"country": "KR"
}
],
"false": [
{
"name": "Robin",
"age": 22,
"country": "CA"
},
{
"name": "Doe",
"age": 13,
"country": "US"
},
{
"name": "Smith",
"age": 20,
"country": "KR"
}
]
}
브라우저 지원
groupBy()
API는 공식적으로 지원이 끝난 인터넷 익스플로러(Internet Explorer)를 제외하면 모든 모던 브라우저에서 안전하게 사용할 수 있습니다.
- https://caniuse.com/mdn-javascript_builtins_object_groupby
- https://caniuse.com/mdn-javascript_builtins_map_groupby
마치면서
지금까지 간단한 실습을 통해서 Object.groupBy()
와 Map.groupBy()
메서드를 어떻게 사용하는지 알아보았습니다.
이 두 개의 정적 메서드를 잘 활용하셔서 라이브러리 없이 간결한 코드로 데이터를 효과적으로 분류하실 수 있으셨으면 좋겠습니다.