[javascript] reduce 함수와 싸우기

류태오·2022년 6월 16일
22

Front-end

목록 보기
9/13
post-thumbnail

reduce

    필요없어서 안쓴거야! 했다가 들어가보니 최종 보스 같이 느껴졌던 리듀스.. 하지만 이해하고 보니 쉬웠다. 진작 뜯어볼 걸
  • 함수를 실행하고 하나의 결과값을 반환
  • reduce는 줄이다라는 뜻이며, 누산기라고 이해하면 될 것 같다.

1. 우선 가장 단순화된 형태를 보자

  • 두 개의 인자를 갖는다.
    • acc accumulator : 누산기, 누적되는 값, 최종적으로 출력되는 값
    • cur current : 현재 돌고 있는 요소
const numbers = [4, 3, 2, 1];
let sum = numbers.reduce((acc, cur) => acc + cur)

위를 풀어서보면 아래와 같다.

const numbers = [4, 3, 2, 1];
let sum = numbers.reduce((acc, cur) => {
	return acc + cur;
});

더 풀어서보면 다음과 같다.
acc 에는 가장 첫 번째 원소인 '4'를 할당하고 (index 0)
cur 에는 나머지 원소인 '3, 2, 1'이 순차적으로 들어간다. (index 1, 2 ...)

acc += cur; // 4 += 3;
acc += cur; // 7 += 2;
acc += cur; // 9 += 1;
console.log(acc); // 10

2. 옵션이 추가된 발전된 형태를 보자

  • 2개의 인자 + 1개의 초기값
    • acc accumulator : 누산기, 누적되는 값, 최종적으로 출력되는 값
    • cur current : 현재 돌고 있는 요소
    • initialValue : acc의 초기값 (optional)
const numbers = [4, 3, 2, 1];
let sum = numbers.reduce((accumulator, current) => accumulator + current, 0);
console.log(sum);

여기서 사람 화나게 하는 부분이 initialValue다.
acc의 초기값으로 initialValue를 할당하는 순간 cur는 index 1부터가 아니라 0부터 돌아간다.

같은 배열이지만 index 0의 주인이 달라진다.

acc += cur; // 0 += 4;
acc += cur; // 4 += 3;
acc += cur; // 7 += 2;
acc += cur; // 9 += 1;
console.log(acc); // 10

3. 이제 두 개의 인자를 추가해보자

  • 4개의 인자 + 1개의 초기값
    • acc accumulator : 누산기, 누적되는 값, 최종적으로 출력되는 값
    • cur current : 현재 돌고 있는 요소
    • idx index : 배열 요소의 순서 (optional)
    • arr array (또는 src source) : 현재 배열, 원본 배열 (optional)
    • initialValue : acc의 초기값 (optional)

다음은 평균을 구하는 reduce 함수이다.
마지막에만 나누기를 위해서 index와 arr를 불러왔다.
헷갈려보이지만 주석에 표시된 순서대로 돌면 된다.

const avg = numbers.reduce((acc, cur, index, arr) => {
	if (index === arr.length - 1) { // index가 마지막일 때
		return (acc + cur) / arr.length; // cur - 4
	}
	return acc + cur; // cur - 1, 2, 3
	}, 0);
ㅤ
console.log("avg", avg);

4. 응용편

각 알파벳의 개수를 구하는 reduce 함수

const alphabets = ["a", "a", "c", "c", "c"];const cnt = alphabets.reduce((acc, cur) => {
 if (acc[cur]) {
   acc[cur] += 1;
 } else {
   acc[cur] = 1; // acc.cur이 없으면 선언함
 }
 return acc;
}, {}); // acc는 오브젝트로 선언
 ㅤ
console.log(cnt); // {a: 2, c: 3}
  • 1) 초기값으로 갑자기 빈 오브젝트를 할당하고
  • 2) 오브젝트인데 배열처럼 불러오지 않나...
  • 3) if 구문은 어떻게 되는 것인지..?

난리도 아니다.

우선 오브젝트의 프로퍼티(속성)를 불러오는 법을 알아야한다.
obj["a"]obj.a 은 동일하다.

// 오브젝트의 프로퍼티를 부르는 2가지 방법
const obj = { a: "hey", b: 0, c: 0 };
console.log(obj["a"]); // 'hey"
console.log(obj.a); // "hey"

if 구문 if (acc[cur])을 이해하려면 오브젝트의 프로퍼티 선언방법을 봐야한다.
acc[cur]undefined 인지 아닌지가 중요하다.
처음에는 당연히 빈 오브젝트가 초기값이다보니 undefined 가 된다.
그러면 else 구문에서 처음으로 프로퍼티가 선언되는 것이다.

//  프로퍼티 없을 경우
console.log(obj.j); // undefined
console.log(obj["k"]); // undefined//  프로퍼티 선언
obj.j = 1; // 선언
console.log(obj.j); // 1
 ㅤ
obj["k"] = 2; // 선언
console.log(obj["k"]); // 2

문제 풀이

배운 내용(배열 내장함수)을 바탕으로 3가지 방법으로 풀어보세요.

function countBiggerThanTen(numbers) {
 /** 문제 **/
}const count = countBiggerThanTen([1, 2, 3, 5, 10, 20, 30, 40, 50, 60]);
console.log(count); // 5

1) 첫 번째 풀이법

reduce를 마지막으로 썼던 터라 이 생각 밖에 안났다.

function countBiggerThanTen(numbers) {
 return numbers.reduce((acc, cur) => {
   if (cur > 10) {
     return acc + 1;
   } else {
     return acc;
   }
 }, 0);
}

2) 두 번째 풀이법

딱히 더할 필요가 없다는 것을 깨닫고 필터로 잘라서 개수만 셌더니 코드가 한줄로 해결되었다.

function countBiggerThanTen(numbers) {
 return numbers.filter((el) => el > 10).length;
}

3) 세 번째 풀이법

내가 기존에 항상 코딩하던 방식이다. 변수 범벅으로 ...

function countBiggerThanTen(numbers) {
 let cnt = 0;
 numbers.forEach((element) => {
   if (element > 10) cnt++;
 });
 return cnt;
}

소감

고작 기초 자바스크립트를 풀고 있는 단계지만 전혀 부끄럽지 않고 기초를 다져놓는다는 안도감이 들었다. 항상 불안했었던 부분이 막 기능만들고 페이지만드는데 내 스스로 기초가 너무 부족했다는 점이었다. 마지막에 문제 3개 풀었는데 딱 정답도 저렇게 3가지여서 기분 좋았다. 하하
근데 글 정리하는데 날 밤새웠다. 배우는데 1시간이면 글쓰는데는 3시간 걸리네..

profile
개발하는 디자이너 그리고 실험가

1개의 댓글

comment-user-thumbnail
2024년 11월 5일

이렇게 기초를 파고파고 정리하다보면 다른 문제 풀 때도 응용하게 되는 것 같아요.
글쓰는데 3시간 걸리셨으니까 30년동안 기억하실듯~!

답글 달기