Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

JavaScript로 배열에서 최솟값과 최댓값을 제외한 평균 계산하기

숫자로 이루어진 배열을 입력받아, 배열에서 가장 큰 값과 가장 작은 값을 제외한 나머지 요소들의 평균을 계산하는 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의 특성을 반드시 주의해야 합니다.