1. reduce의 기본 개념
reduce는 배열의 각 요소를 순회하면서, 누적된 값(accumulator)과 현재 처리 중인 요소(currentValue)를 바탕으로 단일 값으로 "축소"하는 함수입니다. 이때, 사용자가 정의한 콜백 함수가 핵심 역할을 합니다.
2. 함수 시그니처와 파라미터
reduce의 기본 형태는 다음과 같습니다:
array.reduce(callback, initialValue);
- callback: 배열의 각 요소마다 실행되는 함수입니다. 이 함수는 네 가지 인자를 받습니다.
- accumulator: 누적값으로, 콜백 함수가 반환한 값이 계속해서 이 변수에 누적됩니다.
- currentValue: 현재 처리 중인 배열 요소입니다.
- currentIndex (선택 사항): 현재 요소의 인덱스입니다.
- array (선택 사항): reduce를 호출한 원래 배열 자체입니다.
- initialValue: (선택적) reduce를 시작할 때 사용할 초기값입니다. 이 값이 제공되면 첫 번째 순회에서 accumulator의 초기값으로 사용되고, currentValue는 배열의 첫 번째 요소부터 시작합니다. 만약 initialValue를 생략하면, 배열의 첫 번째 요소가 초기 accumulator 값이 되며, 순회는 두 번째 요소부터 시작합니다.
3. 작동 원리
reduce는 다음과 같은 순서로 동작합니다:
- 초기 설정:
- initialValue가 주어지면, accumulator는 이 값으로 초기화됩니다.
- initialValue가 없으면, 배열의 첫 번째 요소가 accumulator로 사용되고, 순회는 두 번째 요소부터 시작됩니다.
- 순회 및 누적:
- 배열의 각 요소에 대해 callback 함수가 호출됩니다.
- callback 함수는 accumulator와 현재 요소(currentValue)를 받아 새로운 누적값을 반환합니다.
- 반환된 값은 다음 순회에서 accumulator로 사용됩니다.
- 최종 결과 반환:
- 배열의 모든 요소를 처리한 후, 최종 누적값이 reduce의 결과로 반환됩니다.
forEach와 비교하기
const numbers = [1, 2, 3, 4]
/**
forEach
*/
let total = 0
numbers.forEach(n => total += n)
/**
reduce
*/
// currentValue: 현재 요소
// accumulator: 현재까지 누적된 값(forEach에서 total의 역할)
const total = numbers.reduce((accumulator, currentValue) => {
return accumulator + currentValue
}, 0) // accumulator 초기값 지정
간단한 최소값 찾기와 배열 합계 구하기
/**
최소값 찾기
*/
const smallest = numbers.reduce((accumulator, currentValue) => {
if(accumulator > currentValue) return currentValue
return accumulator
}) // 초기값 스킵 시 accumulator는 배열의 첫 값을 가짐..
/**
합계 구하기
*/
const cart = [
{name: '사과', price: 500},
{name: '바나나', price: 700},
{name: '레몬', price: 300},
]
const sum = cart.reduce((accumulator, currentValue) => {
return accumulator += currentValue.price
}, 0)
4. 사용 예시
예시 1: 배열 합계 계산
const numbers = [1, 2, 3, 4, 5];
// 초기값을 0으로 지정하여 합계를 구함
const sum = numbers.reduce((accumulator, currentValue) => {
return accumulator + currentValue;
}, 0);
console.log(sum); // 출력: 15
- 설명:
- 초기값 0에서 시작하여 배열의 각 요소를 더합니다.
- 각 단계에서 accumulator는 이전까지의 합계가 되고, currentValue는 현재 배열 요소가 됩니다.
예시 2: 배열 평탄화 (Flattening)
const nestedArrays = [[1, 2], [3, 4], [5, 6]];
const flattened = nestedArrays.reduce((accumulator, currentValue) => {
// concat을 사용해 각 내부 배열을 누적 배열에 합칩니다.
return accumulator.concat(currentValue);
}, []);
console.log(flattened); // 출력: [1, 2, 3, 4, 5, 6]
- 설명:
- 초기값으로 빈 배열([])을 사용합니다.
- 각 내부 배열을 accumulator와 합쳐 평탄한 하나의 배열로 만듭니다.
예시 3: 객체 배열에서 특정 속성 합산
const cart = [
{ name: 'apple', price: 1000 },
{ name: 'banana', price: 1500 },
{ name: 'orange', price: 1200 }
];
const totalPrice = cart.reduce((accumulator, item) => {
return accumulator + item.price;
}, 0);
console.log(totalPrice); // 출력: 3700
- 설명:
- 각 객체의 price 속성을 누적해 총합을 계산합니다.
- 초기값 0에서 시작하여 모든 상품 가격을 더합니다.
5. 초기값을 생략했을 때의 주의점
- 초기값 미지정:
만약 initialValue를 생략하면, reduce는 배열의 첫 번째 요소를 accumulator로 사용하고, 순회는 두 번째 요소부터 시작합니다. - 빈 배열 처리:
빈 배열에서 초기값 없이 reduce를 호출하면 오류가 발생합니다. 따라서 빈 배열을 처리할 때는 반드시 초기값을 지정해야 합니다.
6. 다양한 활용 및 장점
- 데이터 집계:
배열의 요소들을 하나의 값으로 축약함으로써, 합계, 평균, 최대/최소값 등 집계 작업에 적합합니다. - 데이터 변환:
배열의 구조를 다른 형태로 변환(예: 객체 매핑, 그룹핑, 평탄화 등)하는 데 유용합니다. - 함수형 프로그래밍 스타일:
reduce는 부수 효과(side effect)를 줄이고, 순수 함수 형태로 데이터를 처리할 수 있도록 도와줍니다.
Reduce와 ForEach 비교
1. 배열의 모든 요소를 이용해 하나의 최종 값을 뽑기
배열의 모든 요소를 순회하며 하나의 결과(누적값)를 만들어내는 방법에는 여러 가지가 있습니다. 여기서는 forEach와 reduce를 이용한 예제를 살펴봅니다.
1-1. forEach를 이용한 합계 계산
목표: 배열 a = [1, 2, 3, 4]의 모든 숫자를 더해 합계를 구합니다.
코드 및 설명:
// 예제 배열 선언
const a = [1, 2, 3, 4];
// forEach 사용: 누적 합계를 저장할 변수를 0으로 초기화합니다.
let total = 0;
// 배열의 각 요소(item)에 대해 반복하면서 total에 누적합니다.
a.forEach((item) => {
total += item; // total = total + item
});
// 최종 합계를 출력합니다.
console.log(total); // 출력 결과: 10
- forEach 메서드:
배열의 각 요소에 대해 제공된 콜백 함수를 실행합니다. 이 방식은 요소를 하나씩 순회하면서 직접 외부 변수(total)를 변경하여 값을 누적합니다. - 주의:
forEach는 반환값이 없으므로, 새로운 값을 리턴받으려면 별도의 변수를 사용해야 합니다.
1-2. reduce를 이용한 합계 계산
목표: 같은 배열 a의 모든 숫자를 더해 합계를 구하는데, 이번에는 reduce를 사용합니다.
코드 및 설명:
// reduce 메서드를 사용하여 배열의 합계를 계산합니다.
// reduce는 두 개의 매개변수를 가진 콜백 함수를 사용합니다.
// - accumulator: 누적된 값 (이전까지의 합)
// - currentValue: 현재 처리 중인 배열 요소
// 그리고 reduce의 두 번째 인자로 초기값을 지정합니다. 여기서는 0입니다.
const totalReduce = a.reduce((accumulator, currentValue) => {
return accumulator + currentValue; // 각 단계마다 누적값에 현재 값을 더함
}, 0); // 0은 초기 accumulator의 값입니다.
console.log(totalReduce); // 출력 결과: 10
- reduce 메서드:
배열의 각 요소를 순회하며, 콜백 함수가 반환하는 값을 누적해 최종 결과를 만듭니다. - 초기값 (Initial Value):
두 번째 인자로 0을 전달하여, 첫 번째 순회 시 accumulator가 0부터 시작하도록 합니다.
2. reduce를 이용한 배열에서 가장 작은 값 찾기
목표: 배열 b = [10, 3, 4, 7]에서 가장 작은 값을 찾습니다.
코드 및 설명:
const b = [10, 3, 4, 7];
// reduce를 사용하여 가장 작은 값을 찾습니다.
// 초기값을 설정하지 않으면, reduce는 배열의 첫 번째 요소(여기서는 10)를
// accumulator의 초기값으로 사용하고, 두 번째 요소부터 순회합니다.
const smallest = b.reduce((accumulator, currentValue) => {
// accumulator와 currentValue 중 작은 값을 반환하여, 다음 순회 시 비교 대상이 됩니다.
if (accumulator > currentValue) {
return currentValue; // 현재 값이 더 작으면 이를 새로운 accumulator로 반환
}
return accumulator; // 그렇지 않으면 기존의 accumulator 유지
});
console.log(smallest); // 출력 결과: 3
- 초기값 미지정 시:
reduce에서 초기값을 전달하지 않으면, 배열의 첫 번째 요소가 자동으로 accumulator로 사용되고, 순회는 두 번째 요소부터 시작합니다. - 비교 로직:
각 순회마다 현재까지의 최소값(accumulator)과 현재 요소(currentValue)를 비교하여, 더 작은 값을 반환합니다.
3. reduce를 이용한 객체 배열에서 특정 속성의 합계 계산
목표: 객체 배열 cart에서 각 객체의 price 값을 모두 더해 총합을 구합니다.
코드 및 설명:
const cart = [
{ name: 'apple', price: 1000 },
{ name: 'lemon', price: 2000 },
{ name: 'banana', price: 300 },
];
// reduce를 사용하여 각 객체의 price 값을 누적합으로 계산합니다.
const cartPrice = cart.reduce((accumulator, currentValue) => {
// currentValue는 객체이므로, 그 안의 price 속성을 누적합니다.
return accumulator + currentValue.price;
}, 0); // 초기 accumulator 값은 0
console.log(cartPrice); // 출력 결과: 3300
- 객체 배열 처리:
각 객체에 대해 특정 속성(price)을 선택하여 누적값에 더합니다. - 초기값 지정:
두 번째 인자로 0을 지정해, 누적합이 0부터 시작하도록 합니다.
결론
- forEach vs reduce:
- forEach는 단순 반복을 통해 외부 변수를 직접 수정하는 방식입니다.
- reduce는 각 요소를 순회하며 하나의 값을 리턴하는 함수형 프로그래밍 기법으로, 누적 로직을 깔끔하게 작성할 수 있습니다.
- 다양한 활용:
- 단순 합계 계산뿐 아니라, 최소값, 최대값, 평균, 객체 배열의 특정 속성 합계 등 다양한 계산을 할 수 있습니다.
- 초기값 설정:
reduce를 사용할 때는 초기값을 명시적으로 설정하는 것이 안전하며, 초기값을 지정하지 않으면 첫 번째 배열 요소가 자동으로 누적값이 됩니다.
이와 같이 reduce를 활용하면 배열의 모든 요소를 하나의 최종 값으로 모을 수 있어, 다양한 상황에서 유용하게 사용할 수 있습니다.
// 배열의 모든 요소를 이용해 하나의 최종 값을 뽑을 수 있다.
const a = [1, 2, 3, 4];
// forEach
let total = 0;
a.forEach((item) => {
total += item;
});
console.log(total);
// reduce
// (currentValue = 현재 요소의 번호 = item)
// (accumulator = 누적된 값 = total = 초기값은 reduce의 두번째 인자로(마지막에) 넣어준다.)
const totalReduce = a.reduce((accumulator, currentValue) => {
return accumulator + currentValue;
}, 0); // 0 = 초기값 = accumulator
// 가장 작은 값 찾기
const b = [10, 3, 4, 7];
// 초기값을 넣지 않으면 첫번째 요소를 스킵하고 첫 요소는 currentValue가 된다.
const smallest = b.reduce((accumulator, currentValue) => {
if (accumulator > currentValue) {
return currentValue;
}
return accumulator;
});
const cart = [
{
name: 'apple',
price: 1000,
},
{
name: 'lemon',
price: 2000,
},
{
name: 'banana',
price: 300,
},
];
const cartPrice = cart.reduce((accumulator, currentValue) => {
return accumulator + currentValue.price;
}, 0);
console.log(cartPrice);'JavaScript' 카테고리의 다른 글
| Bun (1) | 2025.02.11 |
|---|---|
| [JavaScript] 구조 분해 할당 (4) | 2024.12.22 |
| [JavaScript] async & await (6) | 2024.12.20 |
| [JavaScript] 콜백함수 (3) | 2024.12.20 |
| [JavaScript] Fetch, AJAX, Axios (2) | 2024.12.20 |