Search
Duplicate

map,filter,reduce

map

이터러블 프로토콜을 따르는 함수
Iterable 을 순회하며 각각의 값을 function 'f'를 이용해 수행후 반환한다.
/** * @param {function=} f * @param {iterable=} iter */ const map = (f, iter) =>{ let res = []; for (const i of iter){ res.push(f(i)); } return res; }
JavaScript
복사

이터러블 프로토콜을 따른 map의 다형성

iterable protocol을 따르는 객체들은 모두 map을 사용가능하다.
map함수는 iterable protocol을 따르는 for문을 사용하여 순회를 할 수 있다.

querySelectorAll은 map이 동작할까?

NodeList에는 map이 따로 정의되어있지 않기 때문에 동작하지 않는다.
document.querySlectorAll("*").map(...); //error function is not defined (map)
JavaScript
복사

하지만, iterable protocol을 따르기 때문에 순회로직 사용가능.

const map = (f, iter) =>{ let res = []; for (const i of iter){ res.push(f(i)); } return res; } console.log(map(el=>el.nodeName, document.querySelectorAll('*'))); //["HTML", "HEAD", "SCRIPT", "SCRIPT", "BODY"...] function *gen(){ yield 2; yield 3; yield 4; } console.loglog(map(a=>a*a, gen()); // 4, 9, 16
JavaScript
복사

Iterable Protocol을 따를경우 map을 사용할 수 있다. →Iterable Protocol을 따르는 함수들을 사용하는 것은 다른 함수들과의 조합성이 좋아지고 유연성, 다형성이 올라간다고 할 수 있다.

Iterable Protocol을 따랐을 때의 조합성 사례
let m = new Map(); m.set('a', 10); m.set('b', 20); const it = m[Symbol.iterator](); console.log(it.next()); console.log(it.next()); console.log(it.next());
JavaScript
복사

filter

개요

⇒ 배열데이터가 있을때 특정 조건에 맞는 데이터만 추려내는 함수

예제 코드

요구사항
⇒ 3만원 미만인 책의 리스트만 추출하라.
책 원천 데이터
const books = [ {name:"자바의정석", price:40000}, {name:"클린아키텍처", price:28000}, {name:"SQL첫걸음", price:22000}, {name:"MFC윈도우프로그래밍", price:35000}, {name:"토비의스프링", price:98000}, {name:"친절한SQL튜닝", price:50000}, ];
JSON
복사
script
let under30000 = []; for (const book of books) { if (book.price < 30000) { under30000.push(book); } } console.log(under30000); /* 실행 결과 (2) [{…}, {…}] 0: {name: "클린아키텍처", price: 28000} 1: {name: "SQL첫걸음", price: 22000} length: 2 __proto__: Array(0) */
JavaScript
복사
filter 리팩토링
const filter = (f, iter) =>{ let res = []; for (const a of iter) { if(f(a))res.push(a); } return res; }
JavaScript
복사

reduce

개요

배열의 각 요소에 대해 주어진 리듀서(reducer) 함수를 실행하고 하나의 결과값을 반환하는 함수입니다.
배열을 하나의 값으로 축약할 때 사용하는데 이를테면 [1,2,3,4] 라는 배열이 있을 때 reduce를 통해서 얻을 수 있는 기대값은 10입니다.

예제 코드

요구사항
⇒ 배열 [1,2,3,4,5]의 값을 축약한 결과값을 추출하는 함수를 만들어라.
reduce함수 없이 구현
const nums = [1,2,3,4,5]; let totla = 0; for (const n of nums) { total = total + n; } console.log(total) // 15
JavaScript
복사
reduce 함수를 구현
const reduce = (f, acc, iter) =>{ for (const a of iter){ acc = f(acc, a); } return acc; } console.log(reduce(acc, 0, nums)); // 15
JavaScript
복사
acc값을 꼭 사용하지 않아도 동작하도록 로직을 강화해볼 수 있습니다.
reduce 로직 강화
const reduce = (f, acc, iter) =>{ if(!iter){ iter = acc[Symbol.iterator](); acc = iter.next().value; } for (const a of iter){ acc = f(acc, a); } return acc; } console.log(reduce(acc, nums)); // 15
JavaScript
복사
reduce 함수의 인자값으로 초기값(acc)를 주지 않고 바로 함수(f)와 배열(iter)만 넘겨줘도 동작하도록 조건문을 추가해줬습니다.
reduce함수 응용
⇒ 배열뿐 아니라 객체 배열의 조작도 인자로 넘어가는 f 를 어떻게 구현하느냐에 따라 가능해집니다.
위에서 정의했던 책들의 원천데이터를 가지고 reduce함수를 통해 책들의 총 가격을 계산해봅시다.
const books = [ {name:"자바의정석", price:40000}, {name:"클린아키텍처", price:28000}, {name:"SQL첫걸음", price:22000}, {name:"MFC윈도우프로그래밍", price:35000}, {name:"토비의스프링", price:98000}, {name:"친절한SQL튜닝", price:50000}, ]; const reduce = (f, acc, iter) =>{ if(!iter){ iter = acc[Symbol.iterator](); acc = iter.next().value; } for (const a of iter){ acc = f(acc, a); } return acc; } log(reduce((total_price, product)=> total_price+=product.price,0 , books)); //273000
JavaScript
복사
초기값 acc를 total_price로 , books의 book을 인자값으로 받아서 합연산을 해주는 함수를 인자로 넘겨서 합을 도출합니다.

결론

⇒ 이렇게 정의한 reduce 함수의 장점은 함수의 교체가 가능하다는점에 있습니다.
현재는 add 함수를 통해 배열의 덧셈을 해줬지만, 다른 함수를 통해 다른식의 결과 도출 역시 가능해집니다.

map+filter + reduce 중첩 사용과 함수형 사고

위에서 배운 map, filter, reduce를 중첩해서 사용할 수 있습니다.

예제 코드

요구사항
⇒ 책의 원천데이터들 (books)중에서 30,000원 이하의 책들의 총 합 가격은 얼마인지 구하시오.
books data
const books = [ {name:"자바의정석", price:40000}, {name:"클린아키텍처", price:28000}, {name:"SQL첫걸음", price:22000}, {name:"MFC윈도우프로그래밍", price:35000}, {name:"토비의스프링", price:98000}, {name:"친절한SQL튜닝", price:50000}, ];
JSON
복사
map, filter, reduce 함수
const map = (f, iter) => { let res = []; for (const i of iter) { res.push(f(i)); } return res; } const filter = (f, iter) => { let res = []; for (const a of iter) { if (f(a)) res.push(a); } return res; } const reduce = (f, acc, iter) => { if (!iter) { iter = acc[Symbol.iterator](); acc = iter.next().value; } for (const a of iter) { acc = f(acc, a); } return acc; } const add = (a, b) => a + b;
JavaScript
복사
3가지 함수의 중첩 사용 코드
log(reduce(add, 0, map(p => p.price, filter(p => p.price < 30000, books)))); //50000
JavaScript
복사