JavaScript를 다루다 보면 "2009-feb", "2010-jan"처럼 연도와 월이 하나의 문자열로 결합된 데이터를 정렬해야 하는 경우가 종종 있습니다. 이런 형식의 배열을 가장 오래된 날짜부터 최신 날짜 순서(오름차순)로 정렬하는 방법을 알아보겠습니다.
문제 상황
다음과 같이 '연도-월' 형식의 문자열로 구성된 배열이 있다고 가정해 보겠습니다.
const arr = ["2009-feb", "2009-jan", "2010-mar", "2010-jan", "2011-jul", "2011-sep", "2011-jan", "2012-jan", "2012-dec", "2012-feb", "2013-may", "2013-jul", "2013-jun", "2014-jan", "2014-dec", "2014-may", "2015-may", "2015-jan", "2015-jun", "2016-jan", "2016-dec"];
여기서 주의할 점은, 별도의 처리 없이 sort()만 호출하면 문자열이 사전순(알파벳순)으로 정렬되기 때문에 월 이름의 철자 순서대로 정렬되어 의도한 결과를 얻을 수 없다는 것입니다. 따라서 각 요소를 실제 날짜 기준으로 비교하는 커스텀 비교 함수가 필요합니다.
해결 방법
핵심 아이디어는 각 문자열을 하이픈(-) 기준으로 분리한 뒤, 연도는 숫자 그대로 비교하고 월은 영문 약어를 1~12 사이의 숫자로 변환해 비교하는 것입니다.
const arr = ["2009-feb", "2009-jan", "2010-mar", "2010-jan", "2011-jul",
"2011-sep", "2011-jan", "2012-jan", "2012-dec", "2012-feb", "2013-may",
"2013-jul", "2013-jun", "2014-jan", "2014-dec", "2014-may", "2015-may",
"2015-jan", "2015-jun", "2016-jan", "2016-dec"];
const sorter = (a, b) => {
const getDate = date => {
let day = date.split('-');
day[1] = {
jan: 1, feb: 2, mar: 3, apr: 4, may: 5, jun: 6,
jul: 7, aug: 8, sep: 9, oct: 10, nov: 11, dec: 12
}[day[1].substring(0, 3).toLowerCase()] || 0;
return day;
}
const aDate = getDate(a);
const bDate = getDate(b);
return aDate[0] - bDate[0] || aDate[1] - bDate[1];
}
arr.sort(sorter);
console.log(arr);코드 동작 원리
- 문자열 분리:
split('-')으로 각 요소를 연도와 월 두 부분으로 나눕니다. - 월 변환: 월 약어를 소문자로 정규화한 뒤, 미리 정의한 매핑 객체를 통해 1~12의 숫자로 변환합니다. 이 덕분에 'feb'와 'jan'을 알파벳 순서가 아닌 실제 월 순서로 비교할 수 있습니다.
- 우선순위 비교:
aDate[0] - bDate[0] || aDate[1] - bDate[1]표현식은 먼저 연도 차이를 확인하고, 연도가 같아서 차이가 0일 경우에만 월 번호로 비교를 이어갑니다.
실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
[ '2009-jan', '2009-feb', '2010-jan', '2010-mar', '2011-jan', '2011-jul', '2011-sep', '2012-jan', '2012-feb', '2012-dec', '2013-may', '2013-jun', '2013-jul', '2014-jan', '2014-may', '2014-dec', '2015-jan', '2015-may', '2015-jun', '2016-jan', '2016-dec' ]
결과를 보면 모든 항목이 연도 오름차순으로 정렬되고, 같은 연도 내에서는 월 순서대로 배치된 것을 확인할 수 있습니다.
참고: Date 객체를 활용한 대안
월 약어가 표준 형식이라면 Date 객체를 활용해 더 간결하게 처리할 수도 있습니다.
const sortByDate = (a, b) => new Date(a) - new Date(b); arr.sort(sortByDate);
new Date("2009-feb")처럼 비표준 형식의 파싱 결과는 브라우저마다 다를 수 있으므로, 안정성이 중요한 환경에서는 앞서 소개한 명시적인 매핑 방식을 사용하는 것이 좋습니다.