숫자가 임의의 깊이까지 중첩되어 들어 있는 배열이 주어졌을 때, 그 안에서 가장 큰 숫자를 찾아 반환하는 간단한 JavaScript 함수를 작성한다고 가정해 보겠습니다.
const arr = [
15, 24,
[
29, 85, 56,
[
36, 14, 6, 98, 34, 52
],
22
], 87, 60
];예를 들어 다음과 같은 입력 배열이 주어진다면,
const arr = [
34, 65, 67,
[
43, 76, 87, 23, 56, 7,
[
54, 7, 87, 23, 79, 994, 2
],
54
], 54, 4, 2
];함수는 배열 전체에서 가장 큰 값인 다음 결과를 반환해야 합니다.
994
접근 방식: 재귀(Recursion) 활용
중첩의 깊이가 정해져 있지 않기 때문에 단순한 반복문만으로는 모든 요소를 탐색할 수 없습니다. 이럴 때 가장 효과적인 방법은 재귀 함수입니다. 배열의 각 요소를 순회하다가 요소가 배열이면 자기 자신을 다시 호출해 내부를 탐색하고, 숫자라면 현재까지의 최댓값과 비교하는 방식입니다.
핵심 로직 정리
- 초기 최댓값은 어떤 숫자보다도 작은
-Infinity로 설정합니다. - 요소가 배열인지
Array.isArray()로 판별합니다. - 배열이면 재귀 호출로 내부 배열의 최댓값을 구해 현재 최댓값과 비교·갱신합니다.
- 숫자라면 현재 최댓값보다 클 경우 값을 갱신합니다.
- 순회가 끝나면 누적된 최댓값을 반환합니다.
예제 코드
다음은 전체 구현 코드입니다.
const arr = [
34, 65, 67,
[
43, 76, 87, 23, 56, 7,
[
54, 7, 87, 23, 79, 994, 2
],
54
], 54, 4, 2
];
const getGreatest = (arr, greatest = -Infinity) => {
for (let i = 0; i < arr.length; i++) {
// 요소가 배열이면 재귀 호출로 내부 최댓값을 구해 갱신
if (Array.isArray(arr[i])) {
greatest = getGreatest(arr[i], greatest);
continue;
}
// 숫자라면 현재 최댓값과 비교
if (arr[i] > greatest) {
greatest = arr[i];
}
}
return greatest;
};
console.log(getGreatest(arr));주의: 중첩 배열을 만났을 때
return getGreatest(...)처럼 곧바로 반환하면 해당 배열 뒤에 남아 있는 나머지 요소들을 검사하지 못하게 됩니다. 위 코드처럼 재귀 호출의 결과를greatest변수에 누적한 뒤 순회를 계속하는 것이 안전합니다.
출력 결과
콘솔에는 다음과 같은 결과가 출력됩니다.
994
대안: flat()과 Math.max() 활용하기
모든 중첩을 한 번에 펼친 뒤 처리하는 더 간결한 방법도 있습니다.
const greatest = Math.max(...arr.flat(Infinity)); console.log(greatest); // 994
flat(Infinity)는 배열을 완전히 평탄화하므로 중첩 깊이를 신경 쓰지 않고 Math.max()로 최댓값을 바로 구할 수 있습니다. 다만 배열의 크기가 매우 클 경우 스프레드 연산자의 인수 개수 제한으로 인한 오류가 발생할 수 있으므로, 대용량 데이터에는 앞서 소개한 재귀 방식이 더 적합합니다.
마무리
재귀 함수를 활용하면 중첩 깊이에 상관없이 배열의 모든 요소를 빠짐없이 탐색할 수 있습니다. 데이터 양과 상황에 따라 재귀 방식과 flat() 기반 방식 중 적절한 방법을 선택해 사용하시기 바랍니다.