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

JavaScript에서 알파벳·숫자 혼합 배열을 자연스럽게 정렬하는 방법

문자열과 숫자가 섞여 있는 데이터를 정렬할 때는 단순히 sort()만 호출해서는 원하는 결과를 얻기 어렵습니다. 기본 정렬은 사전식(lexicographic) 비교를 수행하기 때문에 'ab-10''ab-2'보다 앞에 오는 등 직관적이지 않은 순서가 나올 수 있습니다.

예를 들어 다음과 같이 알파벳 부분과 숫자 부분이 결합된 배열이 있다고 가정해 보겠습니다. 이 배열을 먼저 알파벳 순으로, 그다음에는 숫자 크기 순으로 정렬하려고 합니다.

const arr = ['Ab-1', 'Ab-11', 'Ab-12', 'ab-10', 'ab-100', 'ab-101', 'ab-2', 'ab-3', 'ab-105'];

영숫자 정렬 구현 예제

핵심 아이디어는 각 문자열을 하이픈(-)을 기준으로 나눈 뒤, 첫 번째 조각은 대소문자를 통일하여 localeCompare()로 비교하고, 두 번째 조각은 숫자로 간주해 차감 비교하는 것입니다. localeCompare()의 결과가 0이면(즉, 알파벳 부분이 같으면) || 연산자 덕분에 이어서 숫자 비교가 수행됩니다.

const arr = ['Ab-1', 'Ab-11', 'Ab-12', 'ab-10', 'ab-100', 'ab-101', 'ab-2', 'ab-3', 'ab-105'];

const alphaNumericSort = (arr = []) => {
  arr.sort((a, b) => {
    const aPart = a.split('-');
    const bPart = b.split('-');
    return aPart[0].toLowerCase().localeCompare(bPart[0].toLowerCase()) || aPart[1] - bPart[1];
  });
};

alphaNumericSort(arr);
console.log(arr);

코드 동작 원리

  • split('-'): 문자열을 하이픈 기준으로 분리해 ['알파벳 부분', '숫자 부분'] 형태의 배열을 만듭니다.
  • toLowerCase() + localeCompare(): 'Ab'와 'ab'처럼 대소문자가 달라도 같은 값으로 취급해 알파벳 순서를 비교합니다.
  • aPart[1] - bPart[1]: 산술 연산 과정에서 자동으로 숫자 변환이 일어나므로 '10'과 '2'를 문자열이 아닌 숫자로 올바르게 비교합니다.

실행 결과

콘솔 출력은 다음과 같습니다.

[
  'Ab-1', 'ab-2',
  'ab-3', 'ab-10',
  'Ab-11', 'Ab-12',
  'ab-100', 'ab-101',
  'ab-105'
]

출력을 보면 알파벳 접두사가 같은 항목끼리 묶인 상태에서 숫자가 오름차순으로 배치된 것을 확인할 수 있습니다. 즉, 'ab-10'이 'ab-2'보다 뒤에 오는 자연스러운(natural) 정렬 순서가 완성됩니다.

참고: localeCompare의 numeric 옵션 활용

모던 자바스크립트 환경에서는 localeCompare(){ numeric: true } 옵션을 지정하는 더 간단한 방법도 있습니다. 이 옵션을 사용하면 문자열 안의 숫자를 실제 숫자 값처럼 취급합니다.

const sorted = [...arr].sort((a, b) =>
  a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })
);
console.log(sorted);

sensitivity: 'base'는 대소문자 차이를 무시한 비교를 의미합니다. 두 가지 방법 모두 파일 이름, 버전 문자열, 제품 코드처럼 영숫자가 섞인 데이터를 정렬할 때 유용하게 활용할 수 있습니다.