문제 상황
예를 들어 다음과 같은 객체 배열이 있다고 가정해 보겠습니다. 각 객체는 id, score, isCut, dnf 네 가지 속성을 가지고 있습니다.
const arr = [
{ id: 1, score: 1, isCut: false, dnf: false },
{ id: 2, score: 2, isCut: false, dnf: false },
{ id: 3, score: 3, isCut: false, dnf: false },
{ id: 4, score: 4, isCut: false, dnf: false },
{ id: 5, score: 5, isCut: true, dnf: true },
{ id: 6, score: 6, isCut: true, dnf: false },
{ id: 7, score: 7, isCut: true, dnf: false },
{ id: 8, score: 8, isCut: true, dnf: false },
{ id: 9, score: 9, isCut: true, dnf: false },
{ id: 10, score: 0, isCut: false, dnf: false },
{ id: 11, score: -1, isCut: false, dnf: false },
{ id: 12, score: -2, isCut: false, dnf: true },
{ id: 13, score: -3, isCut: false, dnf: false },
{ id: 14, score: -4, isCut: false, dnf: false },
{ id: 15, score: -5, isCut: false, dnf: false },
{ id: 16, score: 10, isCut: true, dnf: false }
];이 배열을 다음과 같은 기준으로 정렬해야 합니다.
- dnf가 true인 경우 — 해당 객체는 배열의 맨 아래로 이동하며, 모든 dnf 객체끼리는 score를 기준으로 정렬됩니다.
- isCut이 true인 경우 — 해당 객체는 맨 아래로 이동하되 dnf 객체보다는 위에 위치하며, 모든 isCut 객체끼리는 score를 기준으로 정렬됩니다.
- 나머지 객체 — score를 기준으로 내림차순 정렬하고, 점수가 같으면 id를 기준으로 정렬합니다.
예제 코드
이를 구현한 코드는 다음과 같습니다.
const sortComplex = (arr = []) => {
arr.sort(function (a, b) {
const order = (dnf, isCut) => {
return [0, 1, 3, 2][dnf * 2 + isCut];
}
return order(a.dnf, a.isCut) - order(b.dnf, b.isCut) || b.score - a.score;
});
};
sortComplex(arr);
console.log(arr);코드 동작 원리
핵심은 order 함수입니다. dnf와 isCut이라는 두 불리언 값을 조합하여 각 객체가 속한 그룹의 우선순위를 숫자로 반환합니다.
- dnf: false, isCut: false → 0 (일반 객체)
- dnf: false, isCut: true → 1 (컷 대상 객체)
- dnf: true, isCut: true → 2 (컷 + 미완주 객체)
- dnf: true, isCut: false → 3 (미완주 객체)
이 값을 오름차순으로 비교하면 일반 객체 → isCut 객체 → dnf 객체 순서대로 배치됩니다. 그룹 우선순위가 서로 같을 때는 || 연산자 뒤의 b.score - a.score가 평가되어 score가 높은 객체부터 정렬됩니다. 즉, 앞의 비교 결과가 0일 때만 뒤의 비교가 실행되기 때문에 하나의 비교 함수만으로 다단계 정렬을 깔끔하게 구현할 수 있습니다.
실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
[
{ id: 4, score: 4, isCut: false, dnf: false },
{ id: 3, score: 3, isCut: false, dnf: false },
{ id: 2, score: 2, isCut: false, dnf: false },
{ id: 1, score: 1, isCut: false, dnf: false },
{ id: 10, score: 0, isCut: false, dnf: false },
{ id: 11, score: -1, isCut: false, dnf: false },
{ id: 13, score: -3, isCut: false, dnf: false },
{ id: 14, score: -4, isCut: false, dnf: false },
{ id: 15, score: -5, isCut: false, dnf: false },
{ id: 16, score: 10, isCut: true, dnf: false },
{ id: 9, score: 9, isCut: true, dnf: false },
{ id: 8, score: 8, isCut: true, dnf: false },
{ id: 7, score: 7, isCut: true, dnf: false },
{ id: 6, score: 6, isCut: true, dnf: false },
{ id: 5, score: 5, isCut: true, dnf: true },
{ id: 12, score: -2, isCut: false, dnf: true }
]