문제 소개
이번 문제에서는 공백으로 구분된 3자리 이진수 문자열을 입력받아, 그중 짝수에 해당하는 숫자만 오름차순으로 정렬하고 홀수는 원래 자리에 그대로 두는 JavaScript 함수를 작성해야 합니다.
예를 들어 입력이 '101 111 100 001 010'이라면, 101(십진수 5), 111(7), 001(1)은 홀수이므로 위치가 유지되고, 100(4)과 010(2)처럼 짝수인 값들만 크기순으로 재배열하는 것이 목표입니다.
구현 코드
const str = '101 111 100 001 010';
const sortEvenIncreasing = (str = '') => {
const sorter = (a, b) => {
const findInteger = bi => parseInt(bi, 2);
if (findInteger(a) % 2 === 1 || findInteger(b) % 2 === 1) {
return 0;
}
return findInteger(a) - findInteger(b);
};
const res = str
.split(' ')
.sort(sorter)
.join(' ');
return res;
};
console.log(sortEvenIncreasing(str));
코드 동작 원리
핵심은 Array.prototype.sort()에 전달되는 커스텀 비교 함수입니다. 동작 과정을 단계별로 살펴보겠습니다.
1. 문자열을 배열로 분리
split(' ')을 사용해 공백을 기준으로 문자열을 나누어 각 이진수를 배열의 요소로 만듭니다.
2. 이진수를 십진수로 변환
parseInt(bi, 2)는 이진수 문자열을 십진수 정수로 변환합니다. 예를 들어 parseInt('101', 2)는 5를 반환합니다. 값 비교와 홀짝 판별은 모두 이 십진수 값을 기준으로 수행됩니다.
3. 비교 함수의 분기 처리
비교 대상 두 수 중 하나라도 홀수라면 0을 반환합니다. sort()에서 비교 결과가 0이면 두 요소의 순서를 바꾸지 않으므로, 홀수는 사실상 정렬 대상에서 제외됩니다. 반면 두 수가 모두 짝수라면 findInteger(a) - findInteger(b)를 반환해 값이 작은 쪽이 앞으로 오도록 오름차순으로 정렬합니다.
4. 배열을 다시 문자열로 결합
정렬이 끝난 배열은 join(' ')으로 공백을 사이에 두고 하나의 문자열로 합쳐져 최종 결과가 됩니다.
실행 결과
101 111 100 001 010
비교 함수가 홀수를 포함한 조합에 대해 항상 0을 반환하기 때문에, 홀수는 상대적인 순서를 유지한 채 정렬에서 제외됩니다. 다만 자바스크립트 엔진의 내부 정렬 알고리즘(안정 정렬 여부 등)에 따라 세부적인 요소 배치가 달라질 수 있다는 점은 참고할 필요가 있습니다.
보너스: 짝수 자리를 정확히 유지하며 정렬하기
위 방식은 비교 함수의 특성상 실행 환경에 따라 결과가 미세하게 달라질 수 있습니다. 홀수의 위치를 절대 건드리지 않으면서 짝수가 있던 자리에 정렬된 값을 채워 넣고 싶다면, 짝수만 추출해 정렬한 뒤 다시 끼워 넣는 방식이 더 명확합니다.
const sortEvenSlots = (str = '') => {
const arr = str.split(' ');
const toDec = bi => parseInt(bi, 2);
const evens = arr
.filter(x => toDec(x) % 2 === 0)
.sort((a, b) => toDec(a) - toDec(b));
let idx = 0;
return arr.map(x => toDec(x) % 2 === 0 ? evens[idx++] : x).join(' ');
};
이 코드는 먼저 짝수만 골라내 오름차순으로 정렬한 뒤, 원래 배열을 순회하면서 짝수가 있던 자리에 정렬된 값을 순서대로 채워 넣습니다. 덕분에 어떤 엔진에서 실행하더라도 홀수의 위치는 항상 그대로 유지됩니다.