문제 소개
숫자로 이루어진 배열을 인수로 받아, 최솟값과 최댓값을 제외한 나머지 요소들의 평균을 반환하는 JavaScript 함수를 작성해 보겠습니다.
예를 들어 다음과 같은 배열이 주어졌다고 가정해 봅시다.
const arr = [1, 4, 5, 3, 5, 6, 12, 5, 65, 3, 2, 65, 9];이 배열에서 가장 큰 값(65)과 가장 작은 값(1)을 하나씩 제외한 뒤, 남은 요소들의 평균을 구하는 것이 목표입니다.
풀이 접근 방식
가장 효율적인 방법은 reduce() 메서드를 사용해 배열을 단 한 번만 순회하면서 세 가지 값을 동시에 누적하는 것입니다.
- sum: 배열 전체 요소의 합계
- min: 지금까지 확인한 값 중 최솟값
- max: 지금까지 확인한 값 중 최댓값
누적 초기값으로 min은 Infinity, max는 -Infinity를 사용하면 어떤 숫자와 비교하더라도 올바르게 갱신됩니다.
구현 코드
const arr = [1, 4, 5, 3, 5, 6, 12, 5, 65, 3, 2, 65, 9];
const findExcludedAverage = arr => {
const creds = 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: Infinity,
max: -Infinity,
sum: 0
});
const { max, min, sum } = creds;
// 전체 합에서 최솟값과 최댓값을 빼고, 개수에서도 2를 뺀 값으로 나눈다
return (sum - min - max) / (arr.length - 2);
};
console.log(findExcludedAverage(arr));
출력 결과
콘솔에 출력되는 결과는 다음과 같습니다.
10.818181818181818
코드 설명
동작 과정을 단계별로 살펴보면 다음과 같습니다.
reduce()가 배열의 각 요소를 순회하며 합계(sum)에 값을 더하고, 현재 값이 기존 최댓값보다 크면max를, 최솟값보다 작으면min을 갱신합니다.- 순회가 끝나면
creds객체에는 배열 전체의 합계와 최솟값, 최댓값이 담기게 됩니다. - 마지막으로 전체 합에서 최솟값과 최댓값을 각각 한 번씩 빼고, 요소 개수에서 2를 뺀 값으로 나누어 평균을 구합니다.
예제 배열의 경우 총합은 185이고, 여기서 최솟값 1과 최댓값 65를 빼면 119가 됩니다. 이를 13 − 2 = 11로 나누면 약 10.82라는 결과를 얻을 수 있습니다.
마무리
이처럼 reduce()를 활용하면 별도의 정렬 없이도 최솟값·최댓값을 제외한 평균을 O(n) 시간 복잡도로 간단하게 계산할 수 있습니다. 배열을 정렬한 뒤 양 끝 요소를 잘라내는 방식(O(n log n))보다 효율적이라는 점도 함께 기억해 두시면 좋습니다.