JavaScript로 개발을 하다 보면 객체 배열 안에 또 다른 배열이 중첩되어 있는 데이터 구조를 자주 만나게 됩니다. 이번 글에서는 각 객체가 가진 중첩 배열의 길이(요소 개수)를 기준으로 배열을 내림차순으로 정렬하는 방법을 알아보겠습니다.
문제 상황
다음과 같이 각 객체가 elements라는 중첩 배열 속성을 포함하는 배열이 있다고 가정해 봅시다.
const arr = [
{ name: "Cat1", elements: [
{ name: name, id: id }
]},
{ name: "Cat2", elements: [
{ name: name, id: id },
{ name: name, id: id },
{ name: name, id: id }
]},
{ name: "Cat3", elements: [
{ name: name, id: id },
{ name: name, id: id }
]}
];여기서 요구 사항은 이 배열을 받아서 정렬하는 JavaScript 함수를 작성하는 것입니다. 정렬 기준은 다음과 같습니다.
elements배열에 포함된 요소가 많은 객체일수록 더 앞쪽에 위치해야 합니다.- 즉, 중첩 배열의 길이를 기준으로 내림차순 정렬을 수행합니다.
따라서 정렬이 완료된 후 배열은 다음과 같은 순서가 되어야 합니다.
const output = [
{ name: "Cat2", elements: [ /* 요소 3개 */ ] },
{ name: "Cat3", elements: [ /* 요소 2개 */ ] },
{ name: "Cat1", elements: [ /* 요소 1개 */ ] }
];해결 방법: sort()와 비교 함수 활용
JavaScript의 Array.prototype.sort() 메서드는 비교 함수(comparator)를 인자로 받습니다. 비교 함수는 두 요소 a와 b를 비교하여 음수를 반환하면 a가 앞으로, 양수를 반환하면 b가 앞으로 오도록 정렬합니다. 이 원리를 활용하면 아주 간단하게 해결할 수 있습니다.
예제 코드
const arr = [
{ "name": "Cat1", elements: [
{ "name": "name", "id": "id" }
]},
{ "name": "Cat2", elements: [
{ "name": "name", "id": "id" },
{ "name": "name", "id": "id" },
{ "name": "name", "id": "id" }
]},
{ "name": "Cat3", elements: [
{ "name": "name", "id": "id" },
{ "name": "name", "id": "id" }
]}
];
const sorter = (a, b) => {
if (a.elements.length > b.elements.length) {
return -1;
} else {
return 1;
}
};
arr.sort(sorter);
console.log(JSON.stringify(arr, undefined, 4));더 간결한 표현식
위의 비교 함수는 산술 연산을 사용해 한 줄로 더 간결하게 작성할 수도 있습니다.
arr.sort((a, b) => b.elements.length - a.elements.length);
b의 길이에서 a의 길이를 빼면, a가 더 클 때 음수가 반환되어 a가 앞으로 정렬됩니다. 결과는 동일하며 코드가 훨씬 짧아집니다.
실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
[
{
"name": "Cat2",
"elements": [
{ "name": "name", "id": "id" },
{ "name": "name", "id": "id" },
{ "name": "name", "id": "id" }
]
},
{
"name": "Cat3",
"elements": [
{ "name": "name", "id": "id" },
{ "name": "name", "id": "id" }
]
},
{
"name": "Cat1",
"elements": [
{ "name": "name", "id": "id" }
]
}
]정리 및 주의사항
sort()메서드는 원본 배열을 직접 변경(mutate)합니다. 원본을 유지해야 한다면 먼저 스프레드 연산자나toSorted()(ES2023)를 사용해 복사본을 만든 후 정렬하세요.- 중첩 배열이 존재하지 않는 객체가 섞여 있을 수 있다면
(a.elements?.length || 0)처럼 옵셔널 체이닝으로 안전하게 처리하는 것이 좋습니다. - 오름차순 정렬이 필요하다면 비교 순서만 반대로 바꾸면 됩니다.
이처럼 sort()의 비교 함수만 잘 활용하면 중첩 배열의 길이뿐 아니라 객체의 어떤 속성 기준으로도 자유롭게 정렬할 수 있습니다.