2-2. 컬렉션 중심 프로그래밍 - reduce 활용 (posts, users), countBy, groupBy
— Functional programming — 1 min read
프로그래머스에서 진행한 유인동님의 ES6로 알아보는 동시성 & 함수형 프로그래밍 강의를 들으며 정리한 내용입니다.
# reverseIter()
배열의 값을 거꾸로 순회하며 값을 리턴해주는 제너레이터 함수
1function *reverseIter(arr) {2 let l = arr.length3 while(l--) yield arr[l]4}5
6log(...reverseIter([1, 2, 3])) // 3 2 1
# reduce()
- acc 있는 경우 vs 없는 경우
reduce함수를 쓰는 목적: 인자로 받은 컬렉션을 시작부터 끝까지 순회하며 무언가를 만들 때 사용
- acc 없는 경우: 반드시 acc와 a가 같은 형이라는걸 보장할 수 있을 때 사용
- acc 있는 경우: acc와 a가 다른 형이어도 된다
다만 형이 다를경우, 보조함수의 리턴값이 acc가 되도록 해줘야 함
1// 1. acc 없는 경우2reduce((acc, a) => acc + a, [1,2,3]); // 63
4// 2. acc 있는 경우5/* acc.value += a -> acc에 a를 누적해주고6 * acc -> 리턴 */7reduce((acc, a) => (acc.value += a, acc), [1,2,3], {value: 0}); // 6
() => (a, b)
뒤의 값(b)이 리턴되는 패턴을 활용
1a = 10, 20 // 20 -> 뒤의 값이 리턴됨2a // 103
4var a = 10, b // a와 b가 함께 선언되는것5a // 106b // undefined
# reduce()
활용하기
1. 보조함수를 통해 다양한 기능 수행
1const posts = [2 {id: 1, body: "내용1", comments: [{}]},3 {id: 2, body: "내용2", comments: [{}, {}, {}]},4 {id: 3, body: "내용3", comments: [{}, {}]},5 {id: 4, body: "내용4", comments: [{}]},6];7
8const users = [9 {id: 1, name: "name1", age: 21},10 {id: 2, name: "name2", age: 23},11 {id: 3, name: "name3", age: 20},12 {id: 4, name: "name4", age: 23},13 {id: 5, name: "name5", age: 23},14 {id: 6, name: "name6", age: 21}15];16
17// posts의 comments의 총 수18reduce((count, p)=> (count += p.comments.length, count), posts, 0);19
20// age별 user 그룹21reduce((group, u) => {22 (group[u.age] || (group[u.age] = [])).push(u);23 return group;24}, users, {});25
26// age별 user의 수27reduce((count, u) => 28 (count[u.age] ? count[u.age]++ : count[u.age] = 1, count)29, users, {});
2. 보조함수 incSel()
, pushSel()
를 생성하여 표현을 간결하게 만들어 준다
1function incSel(parent, k) {2 parent[k] ? parent[k]++ : parent[k] = 1;3 return parent;4}5
6function pushSel(parent, k, v) { 7 (parent[k] || (parent[k] = [])).push(v)8 return parent;9}10
11reduce((count, u) => incSel(count, u.age), users, {}); 12// {20: 1, 21: 2, 23: 3}13
14reduce((group, u) => pushSel(group, u.age, u), users, {});15// {20: Array(1), 21: Array(2), 23: Array(3)}
3. 추상도를 더 높인 countBy()
, groupBy()
함수
위의 함수에서 가변적인 부분은 u.age
뿐이다. 추상도를 더 높여 다방면으로 활용가능한 함수를 만들어보자
1const countBy = (f, coll) => reduce((count, a) => incSel(count, f(a)), coll, {});2const groupBy = (f, coll) => reduce((group, a) => pushSel(group, f(a), a), coll, {});3
4countBy(u => u.age, users); // {20: 1, 21: 2, 23: 3}5groupBy(u => u.age, users); // {20: Arr(1), 21: Arr(2), 23: Arr(3)}
ex) countBy()
로 아래의 결과들을 집계할 수 있다
- a로부터 연산한 결과
- a로부터 접근
.get()
결과 - a의 메서드를 실행했을 때의 결과
1// 다방면으로 응용2countBy(n => n, [1,1,2,3,3,3]); // {1: 2, 2: 1, 3: 3}3groupBy(n => n, [1,1,2,3,3,3]); // {1: [1,1], 2: [2], 3: [3,3,3]}4
5const identity = a => a;6const count = data => countBy(identity, data);7
8count([1,1,2,3,3,3]); // {1: 2, 2: 1, 3: 3}
# 인자 이름 arr, coll의 차이 ?
- arr은 형이 반드시 배열일때만 인자이름으로 사용하도록
- coll은
[Symbol.iterator]
이름의 메서드를 가진 순회가능한 모든 컬렉션객체