JavaScript로 개발을 하다 보면 한 배열의 요소들을 다른 배열에 나타난 순서대로 재정렬해야 하는 경우가 종종 있습니다. 예를 들어, 데이터 목록을 사용자가 지정한 우선순위 순서에 맞춰 표시해야 할 때가 대표적입니다.
문제 상황
다음과 같은 두 개의 배열이 있다고 가정해 보겠습니다.
const input = ['S-1','S-2','S-3','S-4','S-5','S-6','S-7','S-8']; const sortingArray = ["S-1", "S-5", "S-2", "S-6", "S-3", "S-7", "S-4", "S-8"];
여기서 우리는 두 개의 배열을 각각 첫 번째, 두 번째 인수로 받는 JavaScript 함수를 작성해야 합니다.
이 함수는 첫 번째 배열의 요소들을 두 번째 배열에서 해당 요소가 위치한 순서를 기준으로 정렬해야 합니다. 즉, 두 번째 배열(sortingArray)이 일종의 '기준 순서표' 역할을 하는 셈입니다.
해결 방법: sort()와 indexOf() 활용
핵심 아이디어는 간단합니다. 비교 함수(comparator) 안에서 각 요소가 기준 배열에서 몇 번째 인덱스에 있는지 indexOf()로 확인한 뒤, 그 차이를 반환하면 됩니다.
const input = ['S-1','S-2','S-3','S-4','S-5','S-6','S-7','S-8'];
const sortingArray = ["S-1", "S-5", "S-2", "S-6", "S-3", "S-7", "S-4", "S-8"];
const sortByReference = (arr1 = [], arr2 = []) => {
const sorter = (a, b) => {
const firstIndex = arr2.indexOf(a);
const secondIndex = arr2.indexOf(b);
return firstIndex - secondIndex;
};
arr1.sort(sorter);
};
sortByReference(input, sortingArray);
console.log(input);코드 설명
sortByReference는 정렬할 배열(arr1)과 기준이 되는 배열(arr2)을 매개변수로 받습니다.- 내부의
sorter비교 함수는 두 요소 a와 b가 기준 배열(arr2)에서 가진 인덱스를 각각 구합니다. firstIndex - secondIndex를 반환함으로써, 기준 배열에서 더 앞에 있는 요소가 먼저 오도록 정렬됩니다.
실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
[ 'S-1', 'S-5', 'S-2', 'S-6', 'S-3', 'S-7', 'S-4', 'S-8' ]
첫 번째 배열(input)이 두 번째 배열(sortingArray)의 순서를 그대로 따르게 된 것을 확인할 수 있습니다.
참고 사항 및 성능 개선 팁
위 방법은 직관적이지만, indexOf()는 호출될 때마다 배열을 처음부터 탐색하므로 O(n)의 시간이 걸립니다. 배열의 크기가 크다면 전체 정렬 복잡도가 O(n² log n)까지 늘어날 수 있습니다.
성능이 중요한 경우에는 기준 배열을 미리 Map 객체로 변환하여 인덱스 조회를 O(1)로 만드는 것이 좋습니다.
const sortByReference = (arr1 = [], arr2 = []) => {
const indexMap = new Map(arr2.map((item, i) => [item, i]));
return [...arr1].sort((a, b) =>
(indexMap.get(a) ?? Infinity) - (indexMap.get(b) ?? Infinity)
);
};이 버전은 원본 배열을 변경하지 않고 새 배열을 반환하며, 기준 배열에 없는 요소는 맨 뒤로 밀어주므로 실무에서 더 안전하게 사용할 수 있습니다.