숫자 리터럴로 구성된 배열이 있고, 이 배열을 인자로 받아 10보다 큰 숫자를 개별 자릿수로 분할한 새로운 숫자 배열을 반환하는 함수(예: splitDigit())를 작성해야 한다고 가정해 봅시다.
문제 이해하기
예를 들어 다음과 같은 입력이 주어졌을 때:
//입력이 다음과 같다면:
const arr = [ 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106 ]
//출력은 다음과 같아야 합니다:
const output = [ 9, 4, 9, 5, 9, 6, 9, 7, 9, 8, 9, 9, 1, 0, 0, 1, 0, 1, 1,
0, 2, 1, 0, 3, 1, 0, 4, 1, 0, 5, 1, 0, 6 ];
즉, 두 자리 이상의 숫자는 각 자릿수로 쪼개져 하나의 평탄화된(flattened) 배열로 만들어져야 합니다.
해결 접근 방식
이 문제는 Array.prototype.reduce() 메서드와 재귀 함수를 조합하여 깔끔하게 해결할 수 있습니다. 먼저 하나의 숫자를 자릿수 배열로 변환하는 재귀 함수 splitNum()을 정의하고, 이후 reduce()를 사용해 배열의 모든 요소에 적용합니다.
코드 구현
const arr = [ 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106 ]
// 하나의 숫자를 자릿수 배열로 분할하는 재귀 함수
const splitNum = (n, res = []) => {
if(n){
return splitNum(Math.floor(n/10), [n % 10].concat(res));
};
return res;
};
// reduce()로 배열 전체에 splitNum을 적용
const splitDigit = (arr) => {
return arr.reduce((acc, val) => acc.concat(splitNum(val)), []);
};
console.log(splitDigit(arr));
동작 원리 살펴보기
- splitNum(n):
n % 10으로 마지막 자릿수를 추출하고,Math.floor(n / 10)으로 나머지 앞부분을 재귀적으로 처리합니다. 결과 배열은concat(res)을 통해 올바른 순서(왼쪽부터 오른쪽)로 유지됩니다. - splitDigit(arr): 초기값
[]에서 시작해 각 숫자를 자릿수 배열로 변환한 뒤 기존 누적 배열에 이어 붙입니다.
실행 결과
콘솔 출력 결과는 다음과 같습니다.
[
9, 4, 9, 5, 9, 6, 9, 7, 9,
8, 9, 9, 1, 0, 0, 1, 0, 1,
1, 0, 2, 1, 0, 3, 1, 0, 4,
1, 0, 5, 1, 0, 6
]
대안: 문자열 변환 활용하기
재귀 대신 String() 변환과 flatMap()을 사용하면 더 간결하게 표현할 수도 있습니다.
const splitDigit = (arr) =>
arr.flatMap(num => String(num).split('').map(Number));
두 방법 모두 동일한 결과를 반환하지만, 재귀 방식은 산술 연산만 사용하고 문자열 변환 방식은 코드가 더 짧고 직관적이라는 장점이 있습니다. 상황에 맞게 선택하여 사용하시면 됩니다.