숫자, 문자열, 그리고 undefined, null, NaN 같은 falsy 값이 뒤섞여 있는 배열을 입력받아, 그중 가장 큰 숫자만 골라내는 자바스크립트 함수를 작성해야 하는 경우가 종종 있습니다.
예를 들어 다음과 같은 배열이 있다고 가정해 보겠습니다.
const arr = [23, 'hello', undefined, null, 21, 65, NaN, 1, undefined, 'hii'];
이 배열에는 유효한 숫자와 함께 문자열, undefined, null, NaN이 섞여 있지만, 함수는 이 중 실제 숫자들만 비교하여 65를 반환해야 합니다.
해결 아이디어
핵심 로직은 다음과 같습니다.
- 최댓값을 담을 변수를
-Infinity로 초기화합니다. 어떤 유한한 숫자보다도 작은 값이므로 안전한 시작점이 됩니다. - 배열을 순회하면서 각 요소를 단항 더하기 연산자(
+)로 숫자로 변환합니다. - 변환 결과가 falsy 값(NaN, 0, undefined 등)이라면 해당 요소는 건너뛰고(
continue), 유효한 숫자라면Math.max()로 최댓값을 갱신합니다.
예제 코드
const arr = [23, 'hello', undefined, null, 21, 65, NaN, 1, undefined, 'hii'];
const pickBiggest = arr => {
let max = -Infinity;
for(let i = 0; i < arr.length; i++){
if(!+arr[i]){
continue;
};
max = Math.max(max, +arr[i]);
};
return max;
};
console.log(pickBiggest(arr));실행 결과
위 코드를 실행하면 콘솔에 다음과 같은 결과가 출력됩니다.
65
대안: filter와 스프레드 문법 활용하기
반복문 대신 filter()와 스프레드 문법을 조합하면 코드를 한 줄로 더 간결하게 표현할 수도 있습니다.
const pickBiggest = arr =>
Math.max(...arr.filter(v => typeof v === 'number' && !Number.isNaN(v)));
console.log(pickBiggest(arr)); // 65이 방식은 타입 검사를 명시적으로 수행하므로 의도를 더 분명하게 드러낸다는 장점이 있습니다. 다만 배열이 매우 클 경우 스프레드 연산자에 인수 개수 제한이 있을 수 있으므로, 대용량 데이터에는 반복문 방식이 더 안전합니다.
주의할 점
- 배열에 유효한 숫자가 하나도 없다면 두 방식 모두
-Infinity를 반환하므로, 필요하다면 이 경우에 대한 별도 처리를 추가하는 것이 좋습니다. +arr[i]변환 시 문자열 형태의 숫자(예:'42')도 숫자로 인정됩니다. 문자열은 완전히 제외하고 싶다면typeof v === 'number'검사를 사용하는 대안 방식이 적합합니다.