reducer - 리듀서

chanto11

·

2020. 12. 29. 16:52

대표적으로 Redux라는 라이브러리는 리듀서를 이용하여 대규모 웹 어플리케이션의 상태관리를 합니다. 그러나 리듀서 함수는 개별적인 데이터 구조의 상태를 변경하는 데도 사용할 수 있습니다.

 

const add = (acc, cur) => acc + cur  //  리듀서 함수
[1,2,3,4,5].reducer(add)  //  => 15 // 리듀서를 실행 시키는 방법

 

우리가 만든 리듀서 add() 함수는 두개의 인자인 acc(accumulator : 누적값) 와 cur(current value : 현재값)이 있습니다.

Array.Reduce() 메서드는 리듀서를 실행하고 배열의 반복이 완료된 후 acc(accumulator : 누적값)를 return합니다. 

acc(accumulator : 누적값)는 선택적으로 호출시 초기값을 셋팅을 할 수 있고 초기값이 없을 시 배열을 첫요소를 초기값으로 갖습니다.

 

위의 내용이 어렵다면 Array.Reduce()의 행위를 코드로 만들어 봅시다.

 

const reduce = (array, reducer, initValue) => {
	
    let acc = (!initValue) ? array.shift() : initValue // 삼항연산자 (조건 ? 참 : 거짓)
    array.forEach((el) => acc = reducer(acc, el)) 
    // 배열의 값을 리듀서(위에 만든 add()함수와 같은)에 누적값과 현재값을 넣어 누적값을 갱신
    return acc
}

let reduce = recude([1,2,3], add)  //  => 6

let reduceWithInitValue = reduce([1,2,3], add, 10)  //  => 16

 

우리가 만든 reduce 함수는 3개의 인자( 배열, 리듀서, 초기값(선택적) )을 가집니다. 그리고

1. Array.shift()를 사용하여 초기값이 없다면 첫번째 요소를 넣어줍니다.

2. 배열의 반복하면서 해당 요소를 리듀서( 위에 만든 add()함수 )에 acc값 과 el (현재 요소값)을 넣어 나온 리턴값을 다     시 acc값에 넣음으로써 acc값을 갱신합니다.

 

위의 과정을 시각화 해보겠습니다.

 

// 초기값이 넣은 경우의 예제
array = [1,2,3], initialValue = 10 

// 첫 번째 반복시
acc = initialValue = 10
cur = 1 
reducer = add(10, 1)
acc = reducer

// 두 번째 반복시
acc = 11
cur = 2
reducer = add(11, 2)
acc = reducer

// 세 번째 반복시
acc = 13
cur = 3
reducer = add(13, 3) 
acc = reducer

// 결과 : result => 16

 

위의 예제는 매번 반복시 acc가 어떻게 증가하는지 보여주고있습니다. 리듀서 함수( 예제의 경우 add() )를 통해 어떻게 cur값이 acc값에 더해지는지 설명할 수 있습니다. 이 방식을 알고 있다면 더욱 더 리듀서를 능숙하게 사용할 수 있습니다.

 

응용하기 (교집합 계산)

교집합 계산을 리듀서를 활용해 다차원 배열을 계산하여 단일 배열로 리턴하는 함수를 작성해봅시다.

 

const intersectionWithRecuce = (...arrays) => {

    //  arrays => [ [ 1, 2, 3, 4 ], [ 2, 3, 4, 9 ], [ 3, 45, 5, 2 ], [3] ] 

	const reducer = (acc, cur) => {
    	cur.filter((curArrayItem) => 
        	acc.includes(curArrayItem)
        );
   	return reduce(arrays, reducer);
};

const intersect = intersectionWithRecuce([[1, 2, 3, 4], [2, 3, 4, 9], [3, 45, 5, 2], [3]])
// => 3

 

위 예제의 리듀서는 배열이 반복되는동안 acc값에는 cur값이 필터링된 배열이 들어오고 필터링된 배열(acc값)을 다시 필터링할 배열로 사용하면서 반복합니다. 좀 더 빠르게 이해 하기위해 아래의 작동방식을 볼까요?

 

// 교집합 구하기 예제 
arrays = [[1, 2, 3, 4], [2, 3, 4, 9], [3, 45, 5, 2], [3]];

// 첫 번째 반복시
acc = [1, 2, 3, 4];
cur = [2, 3, 4, 9];
//cur.filter(arrayItem => acc.includes(arrayItem)
reducer = [2, 3, 4, 9].filter((arrayItem) => [1, 2, 3, 4].includes(arrayItem));

// 두 번째 반복시
acc = [2, 3, 4];
cur = [3, 45, 5, 2];
reducer = [3, 45, 5, 2].filter((arrayItem) => [2, 3, 4].includes(arrayItem));

// 세 번째 반복시
acc = [3, 2];
cur = [3];
reducer = [3].filter((arrayItem) => [3, 2].includes(arrayItem));

// 결과 : Result => [3]

 

리듀서의 개념을 잘 알고있다면 iterable data 처리나 Redux를 사용할 때에 많은 도움이 될 것 같습니다.

 

'Javascript' 카테고리의 다른 글

addEventListener 와 onclick  (0) 2021.01.12
Promise - 프로미스  (0) 2021.01.01
[js] Promise API 의 3가지 상태  (0) 2020.09.04
[js] 자바스크립트 Value  (0) 2020.05.23
[js] 자바스크립트 원시타입  (0) 2020.05.23