14. 고급 배열 마법사 (고급 배열 메서드)/14.3 배열 줄여나가기 (reduce)

14.3.2 `reduce`로 합계, 평균, 최댓값 구하기

thejavascript4kids 2025. 7. 21. 03:19

📘 14.3.2 reduce로 합계, 평균, 최댓값 구하기

안녕하세요, 여러분. 이전 시간에 reduce라는 유용한 도구의 기본 개념을 배웠습니다. 이제는 실제로 reduce를 사용해서 우리 일상에서 자주 필요한 계산들을 해보겠습니다.

바로 합계, 평균, 최댓값, 최솟값 구하기입니다. 마치 우리 반 시험 점수를 정리하는 것처럼, 배열의 숫자들을 가지고 유용한 정보를 만들어내는 방법을 배워보겠습니다. 여러분도 이제 진짜 데이터 분석가가 되어볼 수 있을 거예요.

🧠 새로운 단어들과 친해지기

데이터를 분석할 때 자주 사용하는 기본적인 단어들을 차근차근 설명해드리겠습니다.

단어 의미
합계 모든 숫자를 더한 총합을 의미합니다.
평균 합계를 개수로 나눈 값으로, 전체 데이터의 가운데 정도 값입니다.
최댓값 배열에서 가장 큰 값을 말합니다.
최솟값 배열에서 가장 작은 값을 말합니다.

이런 계산들은 데이터의 특성을 한눈에 파악할 수 있게 도와주는 중요한 정보들입니다.

✨ 통계 계산의 핵심 개념

reduce를 사용한 통계 계산은 데이터를 이해하는 첫 번째 단계입니다. 숫자들이 가득한 배열을 보면 어떤 특징이 있는지 바로 알기 어렵지만, 합계와 평균, 최댓값을 구하면 그 데이터가 어떤 성격을 가졌는지 쉽게 파악할 수 있어요.

합계는 모든 값을 더해서 전체 규모를 알려주고, 평균은 데이터의 가운데 정도 경향을 보여줍니다. 최댓값과 최솟값은 데이터의 범위와 특별한 값을 알려주어, 어떤 값들이 특별히 크거나 작은지 확인할 수 있어요.

이런 기본 계산들을 한 번에 할 수 있다는 것이 reduce의 큰 장점입니다. 배열을 여러 번 돌 필요 없이, 단 한 번의 reduce로 여러 계산을 동시에 구할 수 있어요.

따뜻한 비유: 우리 반 성적표 정리하기

통계 계산을 더 쉽게 이해하기 위해 '선생님이 우리 반 성적표를 정리하는 과정'에 비유해보겠습니다.

시험이 끝나고 나면 선생님은 모든 학생의 점수가 적힌 성적표를 받습니다. 하지만 숫자들만 나열된 표를 보면 우리 반이 어떻게 했는지 한눈에 알기 어렵지요. 그래서 선생님은 계산기를 꺼내서 중요한 정보들을 계산하기 시작합니다.

먼저 모든 점수를 더해서 우리 반의 총점을 구해요(합계). 그다음 총점을 학생 수로 나누어서 반 평균을 계산하지요(평균). 또 점수들을 쭉 훑어보면서 가장 높은 점수가장 낮은 점수를 찾아냅니다(최댓값, 최솟값).

이렇게 계산이 끝나면 선생님은 "우리 반 평균은 85점이고, 최고점은 98점, 최저점은 72점이네요"라고 말씀하실 수 있어요. 복잡한 숫자 나열이 간단하고 의미 있는 정보로 바뀐 거지요!

🎯 통계 계산을 배우는 이유

그렇다면 우리는 왜 reduce로 통계를 계산하는 방법을 배워야 할까요?

첫 번째로, 실생활에서 정말 자주 사용되기 때문입니다. 용돈 관리, 시험 점수 분석, 운동 기록 정리 등 숫자가 있는 곳이면 어디든 통계가 필요해요.

두 번째로, 복잡한 데이터를 간단하게 요약할 수 있습니다. 100개의 숫자가 있어도 몇 개의 계산으로 전체 상황을 파악할 수 있어요.

세 번째로, 의사결정에 도움이 됩니다. 예를 들어 어떤 게임의 최고 점수를 알면 목표를 세울 수 있고, 평균 점수를 알면 자신의 실력을 객관적으로 평가할 수 있어요.

마지막으로, 프로그래밍에서 데이터 분석의 기초가 되기 때문입니다. 나중에 더 복잡한 분석을 할 때도 이런 기본 계산들이 출발점이 됩니다.

⚙️ 기본 사용법 살펴보기

각각의 계산을 하는 기본적인 reduce 패턴을 알아보겠습니다.

// 합계 구하기
let sum = numbers.reduce(function(total, current) {
    return total + current;
}, 0);

// 평균 구하기 (합계를 개수로 나누기)
let average = sum / numbers.length;

// 최댓값 구하기
let max = numbers.reduce(function(maximum, current) {
    return current > maximum ? current : maximum;
});

// 최솟값 구하기
let min = numbers.reduce(function(minimum, current) {
    return current < minimum ? current : minimum;
});

간단한 예시:

let scores = [85, 92, 78, 96, 88];

let total = scores.reduce((sum, score) => sum + score, 0);
let avg = total / scores.length;
let highest = scores.reduce((max, score) => score > max ? score : max);

console.log("총점:", total);     // 439
console.log("평균:", avg);       // 87.8
console.log("최고점:", highest); // 96

🧪 예제로 익혀보기

이제 실제 상황에서 통계를 계산하는 예제들을 살펴보겠습니다.

🔹 예제 1: 우리 반 키 통계 내기

반 친구들의 키를 측정한 데이터로 다양한 계산을 해보겠습니다.

// 우리 반 친구들의 키 (단위: cm)
let classHeights = [152, 148, 155, 150, 147, 153, 149, 156, 151, 154];

// 키의 총합 구하기
let totalHeight = classHeights.reduce(function(sum, height) {
    return sum + height;  // 지금까지의 합에 현재 키를 더하기
}, 0);

// 평균 키 구하기
let averageHeight = totalHeight / classHeights.length;

// 가장 큰 키 구하기
let tallest = classHeights.reduce(function(max, height) {
    return height > max ? height : max;  // 현재 키가 더 크면 현재 키를, 아니면 기존 최댓값을 반환
});

// 가장 작은 키 구하기
let shortest = classHeights.reduce(function(min, height) {
    return height < min ? height : min;  // 현재 키가 더 작으면 현재 키를, 아니면 기존 최솟값을 반환
});

console.log("우리 반 키 통계:");
console.log("총 키 합계:", totalHeight + "cm");
console.log("평균 키:", averageHeight.toFixed(1) + "cm");
console.log("가장 큰 키:", tallest + "cm");
console.log("가장 작은 키:", shortest + "cm");

이 예제에서는 각각의 계산을 따로따로 해서 우리 반의 키 현황을 자세히 파악합니다.

🔹 예제 2: 한 달 용돈 사용 내역 분석

일주일 동안 사용한 용돈 내역을 분석해서 지출 패턴을 알아보겠습니다.

// 일주일 동안 매일 사용한 용돈 (단위: 원)
let dailyExpenses = [3000, 1500, 2000, 4500, 2500, 5000, 1000];

// 한 번에 모든 계산하기
let expenseStats = dailyExpenses.reduce(function(stats, expense) {
    return {
        total: stats.total + expense,                                        // 총 지출액 계속 더하기
        max: expense > stats.max ? expense : stats.max,                      // 최대 지출 업데이트
        min: expense < stats.min ? expense : stats.min,                      // 최소 지출 업데이트
        count: stats.count + 1                                              // 일수 계산 증가
    };
}, {
    total: 0,          // 총 지출액 시작값
    max: 0,            // 최대 지출 시작값
    min: Infinity,     // 최소 지출 시작값 (매우 큰 수로 시작)
    count: 0           // 일수 시작값
});

// 평균 계산 추가
expenseStats.average = expenseStats.total / expenseStats.count;

console.log("이번 주 용돈 사용 통계:");
console.log("총 사용액:", expenseStats.total + "원");
console.log("하루 평균:", Math.round(expenseStats.average) + "원");
console.log("최대 지출:", expenseStats.max + "원");
console.log("최소 지출:", expenseStats.min + "원");

이 예제에서는 하나의 reduce로 여러 계산을 동시에 하는 효율적인 방법을 보여줍니다.

🔹 예제 3: 게임 점수 기록 분석

좋아하는 게임의 점수 기록을 분석해서 실력 향상을 확인해보겠습니다.

// 최근 10게임의 점수 기록
let gameScores = [1200, 1450, 980, 1600, 1350, 1100, 1520, 1280, 1420, 1550];

// 계산 기능 만들기
function analyzeGameScores(scores) {
    if (scores.length === 0) {
        return "점수 기록이 없어요.";
    }

    let sum = scores.reduce((total, score) => total + score, 0);            // 총점수 계산
    let average = sum / scores.length;                                      // 평균 계산
    let best = scores.reduce((max, score) => score > max ? score : max);    // 최고점수 계산
    let worst = scores.reduce((min, score) => score < min ? score : min);   // 최저점수 계산

    return {
        총게임수: scores.length + "게임",
        총점수: sum + "점",
        평균점수: Math.round(average) + "점",
        최고점수: best + "점",
        최저점수: worst + "점",
        점수차이: (best - worst) + "점 차이"
    };
}

let gameStats = analyzeGameScores(gameScores);
console.log("게임 점수 분석 결과:");
console.log(gameStats);

이 예제에서는 계산을 함수로 만들어서 다시 사용할 수 있도록 하고, 결과를 보기 좋게 정리합니다.

🔄 통계 계산 과정 정리

지금까지 배운 계산 과정을 단계별로 정리해보겠습니다.

첫 번째 단계는 데이터 준비입니다. 분석하고 싶은 숫자들이 담긴 배열을 준비하는 거예요. 점수, 키, 용돈 등 어떤 숫자든 가능합니다.

두 번째는 필요한 계산 선택 단계입니다. 합계, 평균, 최댓값, 최솟값 중에서 어떤 정보가 필요한지 결정해야 해요.

세 번째는 reduce 함수 작성 단계입니다. 각 계산에 맞는 계산 로직을 reduce 함수로 만듭니다. 이때 적절한 시작값 설정이 중요해요.

마지막으로 결과 활용 단계입니다. 계산된 결과를 화면에 출력하거나, 다른 계산에 사용하거나, 의사결정에 활용할 수 있습니다.

🧠 자주 하는 실수와 주의할 점

통계 계산을 할 때 초보자들이 자주 하는 실수들을 알아보고 피하는 방법을 살펴보겠습니다.

❌ 실수 1: 빈 배열로 평균을 계산하려고 하기

// 위험한 예시 - 빈 배열
let emptyScores = [];
let badAverage = emptyScores.reduce((sum, score) => sum + score, 0) / emptyScores.length;
console.log(badAverage); // NaN (0을 0으로 나눈 결과)

// 안전한 방법
function safeAverage(numbers) {
    if (numbers.length === 0) {
        return "데이터가 없어요";
    }
    let sum = numbers.reduce((total, num) => total + num, 0);  // 합계 계산
    return sum / numbers.length;                               // 평균 계산
}

console.log(safeAverage([])); // "데이터가 없어요"
console.log(safeAverage([10, 20, 30])); // 20

빈 배열로 나누면 NaN(숫자가 아님)이 나오므로 반드시 배열 길이를 먼저 확인해야 합니다.

❌ 실수 2: 최댓값/최솟값 시작값을 잘못 설정하기

// 음수만 있는 배열
let negativeNumbers = [-5, -10, -3, -8];

// 잘못된 방법 - 0으로 시작
let wrongMax = negativeNumbers.reduce((max, num) => 
    num > max ? num : max, 0
);
console.log(wrongMax); // 0 (틀렸어요! 실제 최댓값은 -3)

// 올바른 방법
let correctMax = negativeNumbers.reduce((max, num) => 
    num > max ? num : max  // 첫 번째 요소를 시작값으로 사용
); 

console.log(correctMax); // -3

최댓값과 최솟값을 구할 때는 시작값을 잘못 설정하면 엉뚱한 결과가 나올 수 있어요.

❌ 실수 3: 소수점이 너무 길게 나오는 문제

// 계산 결과가 보기 어려움
let prices = [1500, 2300, 1800];
let average = prices.reduce((sum, price) => sum + price, 0) / prices.length;
console.log("평균 가격:", average); // 1866.6666666666667

// 보기 좋게 정리
let niceAverage = Math.round(average);                    // 반올림하기
console.log("평균 가격:", niceAverage + "원"); // 1867원

// 또는 소수점 첫째 자리까지
let oneDecimal = average.toFixed(1);                      // 소수점 1자리로 고정
console.log("평균 가격:", oneDecimal + "원"); // 1866.7원

나눗셈 결과는 소수점이 길게 나올 수 있으므로 적절히 반올림하거나 자릿수를 제한해야 합니다.

✏️ 연습문제로 개념 다지기

이제 우리가 배운 것들을 직접 만져보는 시간입니다. 마치 새로 익힌 곡을 연주해보는 연주자처럼, 천천히 손가락 하나하나 움직여보겠습니다. 완벽하지 않아도 괜찮아요. 그 과정 자체가 배움이니까요.

배운 내용을 연습문제를 통해 확실히 익혀보겠습니다.

Ex1) 반 친구들의 몸무게로 평균 몸무게를 구하는 "우리 반 평균 몸무게 계산기" 만들어보자

// 반 친구들의 몸무게 (단위: kg)
let classWeights = [42, 38, 45, 40, 43, 39, 44, 41, 46, 37];

// 총 무게 구하기
let totalWeight = classWeights.reduce(function(sum, weight) {
    return sum + weight;  // 지금까지의 합에 현재 몸무게를 더하기
}, 0);

// 평균 무게 구하기
let averageWeight = totalWeight / classWeights.length;

console.log("반 친구들 몸무게:", classWeights + "kg");
console.log("총 무게:", totalWeight + "kg");
console.log("평균 몸무게:", averageWeight.toFixed(1) + "kg");

Ex2) 일주일 기온에서 가장 높은 날과 낮은 날을 찾는 "이번 주 날씨 분석기" 만들어보자

// 일주일간 최고 기온 (단위: 도)
let weeklyTemps = [28, 31, 25, 33, 29, 27, 30];

// 최고 기온 찾기
let hottestDay = weeklyTemps.reduce(function(max, temp) {
    return temp > max ? temp : max;  // 현재 온도가 더 높으면 현재 온도를, 아니면 기존 최고를 반환
});

// 최저 기온 찾기
let coldestDay = weeklyTemps.reduce(function(min, temp) {
    return temp < min ? temp : min;  // 현재 온도가 더 낮으면 현재 온도를, 아니면 기존 최저를 반환
});

console.log("이번 주 기온:", weeklyTemps + "도");
console.log("가장 더운 날:", hottestDay + "도");
console.log("가장 추운 날:", coldestDay + "도");
console.log("기온 차이:", (hottestDay - coldestDay) + "도");

Ex3) 책 읽기 기록의 총 페이지와 평균 페이지를 계산하는 "독서 기록 분석기" 만들어보자

// 이번 달에 읽은 책들의 페이지 수
let bookPages = [120, 89, 156, 203, 95, 178, 134];

// 총 페이지 수
let totalPages = bookPages.reduce(function(sum, pages) {
    return sum + pages;  // 지금까지 읽은 페이지에 현재 책 페이지를 더하기
}, 0);

// 평균 페이지 수
let averagePages = totalPages / bookPages.length;

console.log("읽은 책들:", bookPages + "페이지");
console.log("총 읽은 페이지:", totalPages + "페이지");
console.log("책 한 권 평균:", Math.round(averagePages) + "페이지");
console.log("읽은 책 권수:", bookPages.length + "권");

🤔 심화 문제로 실력 확인하기

더 깊이 있는 문제들을 통해 통계 계산에 대한 이해를 확인해보겠습니다.

Q1. 통계를 구하는 것이 왜 중요한지 친구에게 설명해보세요.

정답: "통계는 마치 우리 반의 '성적표 요약본' 같아요. 30명의 점수를 모두 외울 수는 없지만, 평균 점수와 최고점, 최저점만 알면 우리 반이 어떻게 했는지 쉽게 파악할 수 있잖아요. 숫자가 많을 때 중요한 정보만 뽑아서 이해하기 쉽게 만들어주는 거예요."

Q2. 다음 데이터에서 어떤 문제가 있을까요?

let scores = [];
let average = scores.reduce((sum, score) => sum + score, 0) / scores.length;

정답: 빈 배열을 0으로 나누려고 해서 NaN(숫자가 아님)이 나올 거예요. 평균을 구하기 전에 배열에 데이터가 있는지 먼저 확인해야 해요.

📚 13단원 복습 - 비동기 처리 기억하기

14단원을 계속 배우기 전에 지난 시간에 배운 비동기 처리에 대해 간단히 복습해볼까요?

복습 문제 1: 비동기 처리 순서 이해하기

// 다음 코드의 실행 순서를 맞춰보세요
console.log("1");

setTimeout(function() {
    console.log("2");
}, 0);

console.log("3");

// 정답: "1" → "3" → "2"
// 해설: setTimeout은 비동기로 실행되므로 시간이 0이어도 
// 동기 코드가 모두 끝난 후에 실행됩니다.

복습 문제 2: fetch로 간단한 API 호출하기

// 다음 코드를 완성해서 사용자 정보를 가져와보세요

async function getUser(userId) {
    try {
        let response = await fetch(`https://api.example.com/user/${userId}`);

        if (response.ok) {
            let user = await response.json();
            console.log("사용자 정보:", user.name);
            return user;
        } else {
            console.log("사용자를 찾을 수 없습니다");
            return null;
        }
    } catch (error) {
        console.log("네트워크 오류:", error.message);
        return null;
    }
}

// 사용법
getUser(123);

// 정답: response.ok로 응답 상태를 확인하고, 
// try-catch로 네트워크 오류를 처리해야 합니다.

🧚‍♀️ 이야기로 다시 배우기: 스포츠 기록 관리자

마지막으로 통계 계산을 하나의 재미있는 이야기로 정리해볼까요?

어느 학교에 체육 선생님 스탯(Stats)이라는 분이 계셨습니다. 이 선생님은 학생들의 운동 기록을 관리하는 일을 맡고 있었는데, 정말 꼼꼼하고 체계적이기로 유명했답니다.

어느 날, 6학년 축구부 친구들이 100m 달리기 시합을 했어요. 10명의 기록이 나왔는데: 15.2초, 16.1초, 14.8초, 15.7초, 16.4초, 14.5초, 15.9초, 15.3초, 16.0초, 15.1초였어요.

스탯 선생님은 이 기록들을 보고 바로 계산기를 꺼내셨습니다. "총 기록 시간이 얼마나 될까?" 하시면서 모든 시간을 더하기 시작했어요(합계). 그다음에는 "평균 기록은 얼마일까?" 하시며 총합을 10으로 나누셨지요(평균).

"이번에는 가장 빠른 친구는 누구일까?" 하시면서 기록들을 하나씩 비교해서 14.5초를 찾아내셨어요(최솟값). 마지막으로 "가장 느린 기록은 몇 초일까?" 하시며 16.4초를 찾으셨답니다(최댓값).

이렇게 계산을 마친 스탯 선생님은 칠판에 이렇게 써 주셨어요:

  • 총 달린 시간: 155.0초
  • 평균 기록: 15.5초
  • 최고 기록: 14.5초
  • 느린 기록: 16.4초

축구부 친구들은 "와! 우리 평균이 15.5초네! 지난번보다 0.3초 빨라졌어!"라며 기뻐했어요. 복잡한 숫자들이 간단하고 의미 있는 정보로 바뀌어서, 자신들의 실력 향상을 쉽게 확인할 수 있었거든요.

이처럼 reduce를 사용한 통계 계산은 데이터 속에 숨어있는 의미를 찾아내는 훌륭한 도구입니다. 여러분도 이제 이 방법을 배웠으니, 어떤 숫자 데이터든 의미 있는 정보로 바꿀 수 있게 되었답니다!

지금까지 reduce를 사용해서 기본적인 통계를 계산하는 방법을 배웠습니다. 이런 계산들은 여러분이 데이터를 이해하고 분석하는 데 정말 유용한 도구가 될 것입니다.

✅ 학습 완료 체크리스트

이번 시간에 배운 내용들을 모두 이해했는지 확인해보세요!

학습 내용 이해했나요?
통계 계산의 기본 개념
기본 사용법과 문법
주요 특징과 차이점
자주 하는 실수들
실전 예제 이해

📂 마무리 정보

오늘 배운 14.3.2 내용이 여러분의 자바스크립트 지식 상자에 잘 저장되었나요? 다음 시간에는 더 재미있는 내용으로 만나요!

기억할 점: 오늘 배운 내용을 꼭 연습해보시고, 궁금한 점이 있으면 언제든 다시 돌아와서 읽어보세요.


🚀 더 체계적인 JavaScript 학습을 원하신다면?
이 포스팅에서 다룬 내용을 실제로 실습해보세요!
무료 JavaScript 학습 플랫폼에서 단계별 학습과 실시간 코드 실행을 통해
더욱 효과적이고 재미있게 학습하실 수 있습니다.
📝 실시간 코드 실행 📊 학습 진도 관리 👥 체계적 커리큘럼
📚 171개 체계적 학습레슨 · 📋 855개 4지선다 연습문제 · 🆓 완전 무료 · ⚡ 즉시 시작