JavaScript: reduce()를 알아보자~

다잉·2025년 2월 6일

JS

목록 보기
7/9

참 많고 많은 배열의 메서드가 있지만 잘 활용하지 못한다는 생각이 드는 오늘입니다..ㅎㅎ

오늘의 공부 주제는 reduce() 친구입니다! 이 친구가 굉장히 강력한 녀석이라고 하더라구요. 은근 활용법들이 많아서 한 번 차근차근 정리해보려고 합니다.

reduce()

기본 문법
array.reduce(<콜백함수>, <초기값>);

//예시 코드
const array1 = [1, 2, 3, 4];

// 0 + 1 + 2 + 3 + 4
const initialValue = 0;
const sumWithInitial = array1.reduce(
  (accumulator, currentValue) => accumulator + currentValue,
  initialValue,
);

console.log(sumWithInitial);
// Expected output: 10

MDN
DaleSeo

reduce() 메서드는 배열의 각 요소에 대해 주어진 콜백 함수(reducer 함수)를 실행하고, 하나의 결과값을 반환한다.

콜백 함수(reducer 함수)에는 총 4개의 인자를 가지지만, 대부분의 경우에는 첫 2개의 인자만 필요합니다.

  • accumulator: 이전 요소를 상대로 콜백 함수를 실행한 결과(누적자)

  • currentValue: 현재 요소의 값

  • currentIndex: 현재 요소의 인덱스 (initialValue를 제공한 경우 0, 아니면 1부터 시작)

  • array: reduce() 메서드를 호출하는 배열

  • initialValue: 콜백의 최초 호출에서 첫 번째 인수에 제공하는 값. 초기값을 제공하지 않으면 배열의 첫 번째 요소를 사용. 빈 배열에서 초기값 없이 reduce()를 호출하면 오류가 발생함!

콜백 함수의 반환 값은 accumulator에 할당되고, 누적된 값은 순회 중에 유지되므로 결국 최종 결과는 하나의 값이 됩니다.


reduce()의 활용

누적 계산

reduce()의 가장 기본적인 활용은 누적 계산을 할 때!

//배열에 들어있는 숫자의 누적합 구하기

const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // 10

👉 sumconst 키워드로 선언하여 변경하지 못하게 할 수 있기에 더 견고한 코드 작성 가능

최소값, 최대값 계산

//숫자 배열에서 최소값, 최대값 계산

const numbers = [1, 2, 3, 4];
const min = numbers.reduce((min, num) => (min < num ? min : num));
console.log(min); // 1
const max = numbers.reduce((max, num) => (max > num ? max : num));
console.log(max); // 4

👉 초기값을 생략함: 배열의 첫 번째 값이 초기값으로 사용 됨

개수 세기

reduce()는 원소의 개수를 셀 때에도 많이 사용합니다!

//배열에 들어 있는 각 과일의 개수 세기

const fruits = ["apple", "banana", "apple", "orange", "banana", "apple"];
const fruitCounts = fruits.reduce(
  (counter, fruit) => ({
    ...counter,
    [fruit]: fruit in counter ? counter[fruit] + 1 : 1,
  }),
  {}
);
console.log(fruitCounts); // { apple: 3, banana: 2, orange: 1 }

타입스크립트 주의 사항

타입스크립트에서 reduce() 메서드를 사용할 때는 타입 오류가 발생하기 쉽습니다.

개수 세기에서의 예시 코드 같은 경우에는 초기값으로 빈 객체를 넘기기 때문에, counter의 타입이 빈 객체로 추론되기 때문입니다.

타입 오류를 해결하려면 fruits.reduce<{ [key: string]: number }>(와 같이reduce<결과 타입>의 형태로 결과 값의 타입을 표시해주면 됩니다. 또는 타입스크립트의 유틸리티 타입인 Record를 활용해도 됩니다.

배열 평탄화

2차원 배열을 1차원 배열로 평탄화할 때도 쓰일 수 있습니다!

const nested = [
  [1, 2],
  [3, 4],
  [5, 6],
];
const flattened = nested.reduce((nums, num) => [...nums, ...num], []);
console.log(flattened); // [1, 2, 3, 4, 5, 6]

속성 추출

객체 배열에서 특정 속성의 값만 추출하고 싶을 때도 사용 가능합니다!

//각 사용자의 country 값을 중복 없이 수집

const users = [
  { name: "John", age: 25, country: "US" },
  { name: "Jane", age: 30, country: "KR" },
  { name: "Robin", age: 22, country: "CA" },
  { name: "Doe", age: 13, country: "US" },
  { name: "Smith", age: 20, country: "KR" },
];
const distinctCountries = users.reduce((countries, user) => {
  countries.add(user.country);
  return countries;
}, new Set()); //초기값: Set(중복을 허용하지 않는 유일한 값 집합, 국가 값을 추가할 때 자동으로 중복 제거됨)
console.log(distinctCountries); // { "US",  "KR", "CA" }

초기값으로 자료구조인 Set를 사용했는데, 이와 관련한 자세한 개념은 따로 정리해서 올려야겠습니당..ㅎ

원소 분류

reduce()는 데이터를 그룹화할 때 빛을 발한다고 합니다.

// 사용자 배열을 국가 기준으로 분류

const users = [
  { name: "John", age: 25, country: "US" },
  { name: "Jane", age: 30, country: "KR" },
  { name: "Robin", age: 22, country: "CA" },
  { name: "Doe", age: 13, country: "US" },
  { name: "Smith", age: 20, country: "KR" },
];
const usersByCountry = users.reduce((users, user) => {
  const country = user.country;
  if (!(country in users)) {
    users[country] = [];
  }
  users[country].push(user);
  return users;
}, {});
console.log(usersByCountry);

reduce()를 사용해서 이렇게 분류를 하게 되면, 각 국가를 키로 해당 국적자 목록 객체가 만들어집니다.

{
  US: [
    { name: "John", age: 25, country: "US" },
    { name: "Doe", age: 13, country: "US" }
  ],
  KR: [
    { name: "Jane", age: 30, country: "KR" },
    { name: "Smith", age: 20, country: "KR" }
  ],
  CA: [
    { name: "Robin", age: 22, country: "CA" }
  ],
}

마무리

사실 문제 풀면서 단순히 누적 계산을 하려고 찾아본 reduce()였으나.. 활용도가 높은 메서드였다는 사실에 큰 깨달음을 얻게 되었습니다.

아직은 체화시키기 어려운 것 같지만 빠르게 습득해보길~!
나 자신 화이탱❗

profile
멋쟁이가 되는 그날까지

0개의 댓글