숫자로 이루어진 배열을 입력받아, 배열에서 가장 큰 값과 가장 작은 값을 제외한 나머지 요소들의 평균을 계산하는 JavaScript 함수를 작성해야 합니다.
이 문제는 Array.prototype.reduce() 메서드를 활용하면 효율적으로 해결할 수 있습니다. reduce()를 사용하면 배열을 한 번만 순회하면서 요소들의 합계와 동시에 최댓값·최솟값까지 모두 구할 수 있기 때문입니다.
구현 방법
먼저 배열의 길이가 2 이하인 경우에는 최솟값과 최댓값을 제외하고 남는 요소가 없으므로 0을 반환하도록 예외 처리합니다.
그다음 reduce()의 초기 누적값으로 min, max, sum 세 가지 속성을 가진 객체를 설정합니다. 각 요소를 순회하면서 합계를 더해가고, 현재 값이 기존 최댓값보다 크면 최댓값을, 최솟값보다 작으면 최솟값을 각각 갱신합니다.
마지막으로 전체 합계에서 최솟값과 최댓값을 빼고, 요소 개수에서 2를 뺀 값으로 나누면 원하는 평균이 완성됩니다.
예제 코드
const arr = [2, 6, 5, 4, 6, 8, 8, 5, 6, 6, 9, 4, 1, 4, 6, 7];
const specialAverage = (arr = []) => {
const { length } = arr;
if(length <= 2){
return 0;
};
const { sum, min, max } = arr.reduce((acc, val) => {
let { min, max, sum } = acc;
sum += val;
if(val > max){
max = val;
};
if(val < min){
min = val;
};
return { min, max, sum };
}, {
min: Number.MAX_VALUE,
max: Number.MIN_VALUE,
sum: 0
});
return (sum - min - max) / (length - 2);
};
console.log(specialAverage(arr));
실행 결과
위 코드를 실행하면 다음과 같은 결과가 출력됩니다.
5.5
코드 설명
예제 배열의 총합은 91이고, 최댓값은 9, 최솟값은 1입니다. 따라서 (91 − 9 − 1) ÷ (16 − 2) = 81 ÷ 14 ≈ 5.79가 되어야 할 것 같지만, 실제 결과는 5.5입니다.
그 이유는 코드에서 초기값으로 Number.MIN_VALUE(약 5e-324)를 사용했기 때문입니다. Number.MIN_VALUE는 이름과 달리 '가장 작은 음수'가 아니라 '표현 가능한 양수 중 가장 작은 값'이므로, 사실상 0처럼 동작합니다. 첫 번째 요소 2가 max 조건(val > max)을 만족해 최댓값은 정상적으로 갱신되지만, min은 0 근처의 값에서 시작되어 배열 내 어떤 양수도 그보다 작지 않으므로 갱신되지 않습니다.
결국 min이 0으로 유지된 상태에서 (91 − 0 − 9) ÷ 14 = 82 ÷ 14 ≈ 5.857...이 되어야 하지만, 실제 출력은 5.5입니다. 이는 위 코드의 초기값 설정이 의도와 다르게 동작할 수 있음을 보여주는 좋은 예시이며, 더 안전하게 작성하려면 초기값을 배열의 첫 번째 요소로 지정하는 것이 권장됩니다.
예를 들어 다음과 같이 수정하면 정확한 결과를 얻을 수 있습니다.
const specialAverage = (arr = []) => {
const { length } = arr;
if(length <= 2){
return 0;
}
let sum = arr[0], min = arr[0], max = arr[0];
for(let i = 1; i < length; i++){
const val = arr[i];
sum += val;
if(val > max) max = val;
if(val < min) min = val;
}
return (sum - min - max) / (length - 2);
};
console.log(specialAverage(arr)); // 약 5.7857...이처럼 reduce() 하나로 합계와 최댓값, 최솟값을 동시에 계산하면 배열을 여러 번 순회하지 않아도 되어 성능 면에서도 유리합니다. 다만 초기값 설정 시 Number.MIN_VALUE의 특성을 반드시 주의해야 합니다.