Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

JavaScript에서 참조 문자열 배열을 기준으로 객체 배열 정렬하기

JavaScript 개발을 하다 보면 객체 배열을 미리 정의된 순서에 따라 정렬해야 하는 경우가 종종 있습니다. 대표적인 예로, 주문 목록을 상태별 우선순위 순서대로 나열해야 하는데, 그 우선순위가 별도의 문자열 배열에 담겨 있는 경우를 들 수 있습니다.

문제 상황

다음과 같이 객체 배열과 문자열 배열이 있다고 가정해 보겠습니다.

const orders = [
    { status: "pending" },
    { status: "received" },
    { status: "sent" },
    { status: "pending" }
];
const statuses = ["pending", "sent", "received"];

우리가 작성해야 할 함수는 이 두 배열을 입력받아, orders 배열을 statuses 배열의 요소 순서에 맞춰 정렬하는 역할을 합니다. 즉, 첫 번째 배열의 객체들이 두 번째 배열에 나열된 문자열의 순서대로 배치되어야 합니다. 위 예시에서는 'pending' → 'sent' → 'received' 순으로 정렬되어야 합니다.

해결 방법: sort()와 indexOf() 활용

Array.prototype.sort() 메서드에 비교 함수(comparator)를 전달하면 이 문제를 간단히 해결할 수 있습니다. 비교 함수 내부에서 각 객체의 status 값이 참조 배열인 statuses에서 어느 인덱스에 위치하는지 indexOf()로 확인한 뒤, 두 인덱스의 차이를 반환하면 참조 배열의 순서대로 정렬이 완료됩니다.

const orders = [
    { status: "pending" },
    { status: "received" },
    { status: "sent" },
    { status: "pending" }
];
const statuses = ["pending", "sent", "received"];

const sortByRef = (orders, statuses) => {
    const sorter = (a, b) => {
        return statuses.indexOf(a.status) - statuses.indexOf(b.status);
    };
    orders.sort(sorter);
};

sortByRef(orders, statuses);
console.log(orders);

실행 결과

코드를 실행하면 콘솔에 다음과 같이 출력됩니다. 'pending' 객체 두 개가 가장 앞에 위치하고, 이어서 'sent', 마지막에 'received'가 오는 것을 확인할 수 있습니다.

[
    { status: 'pending' },
    { status: 'pending' },
    { status: 'sent' },
    { status: 'received' }
]

성능 개선 팁: Map 사용하기

배열 크기가 큰 경우에는 주의할 점이 있습니다. 위 방식은 비교 함수가 호출될 때마다 indexOf()가 실행되어 선형 탐색(O(n))이 반복되므로, 데이터가 많아지면 정렬 성능이 저하될 수 있습니다. 이런 경우 정렬 전에 Map 객체에 각 상태의 인덱스를 미리 저장해 두면 O(1) 시간에 조회할 수 있어 훨씬 효율적입니다.

const indexMap = new Map(statuses.map((s, i) => [s, i]));
orders.sort((a, b) => indexMap.get(a.status) - indexMap.get(b.status));

참고로 sort()는 원본 배열을 직접 변경(mutation)하므로, 원본을 유지해야 한다면 [...orders].sort(...)처럼 복사본을 정렬하는 것이 좋습니다.