📚 이론정리/JS & TS

✏️ Reduce 함수

서카츄 2024. 1. 3. 19:16

Reduce는 배열의 모든 요소를 순회하면서 하나의 결과값을 만들어내는 배열 메서드이다

"배열" 메서드 인게 중요!

 

 

 

기본 문법

// reduce의 기본 문법
array.reduce((누적값, 현재값) => {
  // 계산 로직
  return 새로운누적값;
}, 초기값);

 

 

 

예시)

// 1. 숫자 배열의 합계 구하기 
const numbers = [1, 2, 3, 4, 5];

const sum = numbers.reduce((acc, cur) => {
  console.log(`누적값(acc): ${acc}, 현재값(cur): ${cur}`);
  return acc + cur;
}, 0);

 

 

 

 

이 예시의 실행과정은 이렇게 된다.

// 실행 과정:
// 1단계: acc: 0, cur: 1 => 반환값: 1
// 2단계: acc: 1, cur: 2 => 반환값: 3
// 3단계: acc: 3, cur: 3 => 반환값: 6
// 4단계: acc: 6, cur: 4 => 반환값: 10
// 5단계: acc: 10, cur: 5 => 반환값: 15

 

 

 

 

그래서 결국 sum의 결과값은 15가 된다.

console.log(sum); // 15

 

 

 

 

 


 

초기값을 주지 않는 경우 예시

// 2. 초기값을 주지 않는 경우
const numbers2 = [1, 2, 3, 4, 5];

const sum2 = numbers2.reduce((acc, cur) => {
  console.log(`누적값(acc): ${acc}, 현재값(cur): ${cur}`);
  return acc + cur;
}); // 초기값 없음

 

 

 

실행 과정은 이렇게 진행된다.

// 실행 과정:
// 1단계: acc: 1, cur: 2 => 반환값: 3 (첫 번째 값이 초기값이 됨), 첫번째가 초기값이 되고 현재값은 2부터 시작함(두번째)
// 2단계: acc: 3, cur: 3 => 반환값: 6
// 3단계: acc: 6, cur: 4 => 반환값: 10
// 4단계: acc: 10, cur: 5 => 반환값: 15

 

 

 

 

 


 

다양한 활용 예시

 

1. 최대값 찾기

const numbers = [4, 1, 9, 2, 5];

const max = numbers.reduce((acc, cur) => {
  console.log(`현재 누적값: ${acc}, 현재값: ${cur}, 비교 후 큰 값: ${Math.max(acc, cur)}`);
  return Math.max(acc, cur);
}, 0);

// 실행 과정:
// 1단계: acc: 0, cur: 4 
//    Math.max(0, 4) => 4가 더 크니까 4 반환

// 2단계: acc: 4, cur: 1
//    Math.max(4, 1) => 4가 더 크니까 4 반환

// 3단계: acc: 4, cur: 9
//    Math.max(4, 9) => 9가 더 크니까 9 반환

// 4단계: acc: 9, cur: 2
//    Math.max(9, 2) => 9가 더 크니까 9 반환

// 5단계: acc: 9, cur: 5
//    Math.max(9, 5) => 9가 더 크니까 9 반환

console.log(max); // 9

 

 

 

 

 

 

2. 객체 배열에서 특정 값 합계 구하기

const cart = [
  { item: '사과', price: 1000 },
  { item: '바나나', price: 2000 },
  { item: '딸기', price: 3000 }
];

const totalPrice = cart.reduce((acc, cur) => {
  return acc + cur.price;
}, 0);

console.log(totalPrice); // 6000

 

 

 

 

 

3. 배열을 객체로 반환하기

const fruits = ['apple', 'banana', 'apple', 'orange', 'banana'];

const fruitCount = fruits.reduce((acc, cur) => {
  // 현재 과일이 없으면 1, 있으면 기존 값에 1을 더함
  acc[cur] = (acc[cur] || 0) + 1;
  return acc;
}, {});

console.log(fruitCount); 
// { apple: 2, banana: 2, orange: 1 }

 

더 상세히 적어보기

const fruits = ['apple', 'banana', 'apple', 'orange', 'banana'];

const fruitCount = fruits.reduce((acc, cur) => {
  console.log('현재 상태:', {
    누적객체: acc,
    현재과일: cur,
    해당과일현재개수: acc[cur],
  });
  
  acc[cur] = (acc[cur] || 0) + 1;
  
  console.log('업데이트 후:', acc);
  console.log('------------------------');
  
  return acc;
}, {});  // 초기값으로 빈 객체 {}를 줌

// 실행 과정:
// 1단계: cur = 'apple'
//   acc = {}
//   acc['apple'] = (undefined || 0) + 1 = 1
//   결과: { apple: 1 }

// 2단계: cur = 'banana'
//   acc = { apple: 1 }
//   acc['banana'] = (undefined || 0) + 1 = 1
//   결과: { apple: 1, banana: 1 }

// 3단계: cur = 'apple'
//   acc = { apple: 1, banana: 1 }
//   acc['apple'] = (1 || 0) + 1 = 2
//   결과: { apple: 2, banana: 1 }

// 4단계: cur = 'orange'
//   acc = { apple: 2, banana: 1 }
//   acc['orange'] = (undefined || 0) + 1 = 1
//   결과: { apple: 2, banana: 1, orange: 1 }

// 5단계: cur = 'banana'
//   acc = { apple: 2, banana: 1, orange: 1 }
//   acc['banana'] = (1 || 0) + 1 = 2
//   결과: { apple: 2, banana: 2, orange: 1 }

// 다른 방식으로 작성한 동일한 로직
function countFruits(fruits) {
  const result = {};
  
  for (const fruit of fruits) {
    if (result[fruit]) {
      // 이미 과일이 있으면 개수 증가
      result[fruit] += 1;
    } else {
      // 처음 나온 과일이면 1로 초기화
      result[fruit] = 1;
    }
  }
  
  return result;
}

// 조건부 연산자(||)를 사용하는 이유 설명
const obj = {};
console.log(obj.apple);        // undefined
console.log(undefined || 0);   // 0 (undefined면 0 사용)
console.log(1 || 0);          // 1 (값이 있으면 그 값 사용)

 

 

 

 

 

4. 평균값 찾기

const reviews = [
  { rating: 5, text: "아주 좋아요" },
  { rating: 4, text: "괜찮아요" },
  { rating: 5, text: "최고에요" }
];

const averageRating = reviews.reduce((acc, cur) => {
  return acc + cur.rating;
}, 0) / reviews.length;

console.log(averageRating); // 4.666...

 

const reviews = [
  { rating: 5, text: "아주 좋아요" },
  { rating: 4, text: "괜찮아요" },
  { rating: 5, text: "최고에요" }
];

const averageRating = reviews.reduce((acc, cur) => {
  console.log('현재 상태:', {
    현재까지의합계: acc,
    현재리뷰: cur,
    현재평점: cur.rating
  });
  
  const sum = acc + cur.rating;
  console.log('더한 후:', sum);
  console.log('------------------------');
  
  return sum;
}, 0) / reviews.length;  // 마지막에 리뷰 개수로 나눔

// 실행 과정:
// 1단계
// acc (초기값) = 0
// cur = { rating: 5, text: "아주 좋아요" }
// 0 + 5 = 5

// 2단계
// acc = 5 (이전 단계의 결과)
// cur = { rating: 4, text: "괜찮아요" }
// 5 + 4 = 9

// 3단계
// acc = 9 (이전 단계의 결과)
// cur = { rating: 5, text: "최고에요" }
// 9 + 5 = 14

// 최종 계산
// 전체 합계 = 14
// 리뷰 개수 = 3
// 평균 = 14 / 3 = 4.666...

// for 문으로 작성한 동일한 로직
function calculateAverage(reviews) {
  let sum = 0;
  
  // 합계 계산
  for (const review of reviews) {
    sum += review.rating;
  }
  
  // 평균 계산
  return sum / reviews.length;
}

// 소수점 자리 제한하고 싶다면
const roundedAverage = Number(averageRating.toFixed(1)); // 4.7

// 다양한 활용 예시
const reviewStats = reviews.reduce((acc, cur) => {
  return {
    sum: acc.sum + cur.rating,
    count: acc.count + 1,
    min: Math.min(acc.min, cur.rating),
    max: Math.max(acc.max, cur.rating)
  };
}, { sum: 0, count: 0, min: 5, max: 0 });

console.log({
  평균: reviewStats.sum / reviewStats.count,
  최저평점: reviewStats.min,
  최고평점: reviewStats.max
});