[functional-js] 이터러블 프로토콜을 따르는 map, filter, reduce 함수 구현

younoah·2021년 2월 6일
0

[functional-js]

목록 보기
4/16
post-custom-banner

이 글은 유인동님의 함수형 프로그래밍 강의내용을 정리한 글입니다.

서론

map, filter, reduce 함수들을 매우 유용한 함수들이다. 하지만 배열에서만 사용할 수 있다.

자바스크립트의 환경에서는 배열은 아니더라도 많은 api의 헬퍼 함수들과 값들이 이터러블 프로토콜을 따른다.

따라서 map, filter, reduce 함수들을 이터러블 프로토콜을 따르게 구현하여 사용하면 개발할 때 유용하게 사용할 수 있다.

예를들어 querySelectorAll 메서드로 노드들을 불러오면 배열이 아닌 이터러블 객체인데 이 때 이 노드들을 값으로 하는 이터러블 객체에 map, filter, reduce와 같은 함수들을 적용하게 해보자.

map

이터러블의 모든 요소를 돌면서 매핑되는 요소들의 값으로 새로운 배열로 리턴한다.

구현

const map = (f, iter) => {
  const res = [];
  for (const el of iter) {
    res.push(f(el));
  }
  return res;
};

사용예시

const products = [
  { name: '반팔티', price: 15000 },
  { name: '긴팔티', price: 20000 },
  { name: '핸드폰케이스', price: 15000 },
  { name: '후드티', price: 30000 },
  { name: '바지', price: 25000 },
];

console.log(map(p => p.name, products)); 
// ["반팔티", "긴팔티", "핸드폰케이스", "후드티", "바지"]

console.log(map(p => p.price, products)); 
// [15000, 20000, 15000, 30000, 25000]]

filter

이터러블의 모든 요소를 돌면선 조건에 맞는 요소만 걸러서 새로운 배열로 리턴한다.

구현

const filter = (f, iter) => {
  let res = [];
  for (const a of iter) {
    if (f(a)) res.push(a);
  }
  return res;
};

사용예시

const products = [
  { name: '반팔티', price: 15000 },
  { name: '긴팔티', price: 20000 },
  { name: '핸드폰케이스', price: 15000 },
  { name: '후드티', price: 30000 },
  { name: '바지', price: 25000 },
];

console.log(...filter(p => p.price < 20000, products));
// {name: "반팔티", price: 15000}
// {name: "핸드폰케이스", price: 15000}

console.log(...filter(p => p.price >= 20000, products));
// {name: "긴팔티", price: 20000}
// {name: "후드티", price: 30000}
// {name: "바지", price: 25000}

reduce

이터러블의 모든 요소의 값을 하나의 값으로 (누적하여) 축약한 값을 리턴한다.

구현

const reduce = (f, acc, iter) => {
  if (!iter) { // acc는 옵셔널로 예외처리
    iter = acc[Symbol.iterator]();
    acc = iter.next().value;
  }
  for (const a of iter) {
    acc = f(acc, a);
  }
  return acc;
};

사용예시

const products = [
  { name: '반팔티', price: 15000 },
  { name: '긴팔티', price: 20000 },
  { name: '핸드폰케이스', price: 15000 },
  { name: '후드티', price: 30000 },
  { name: '바지', price: 25000 },
];

console.log(reduce((a, b)=> a + b, 0, [1, 2, 3, 4, 5]));
// 15

console.log(reduce((a, b)=> a + b, [1, 2, 3, 4, 5]));
// 15

console.log(
  reduce((total_price, product) => total_price + product.price, 0, products)
);
// 105000

복합 사용예시

  • 대상 이터러블 객체
const products = [
  { name: '반팔티', price: 15000 },
  { name: '긴팔티', price: 20000 },
  { name: '핸드폰케이스', price: 15000 },
  { name: '후드티', price: 30000 },
  { name: '바지', price: 25000 },
];
  • 제품의 가격만 뽑기
console.log(map(p => p.price, products));
// [15000, 20000, 15000, 30000, 25000]
  • 20000만원 이하의 제품들의 가격만 뽑기
console.log(filter(price => price < 20000, map(p => p.price, products)));
//  [15000, 15000]
  • 20000원 이하의 제품들의 가격의 총합
const add = (a, b) => a + b;

console.log(
  reduce(
    add,
    map(
      p => p.price,
      filter(p => p.price < 20000, products)
    )
  )
);
// 30000

console.log(
  reduce(
    add,
    filter(
      n => n >= 20000,
      map(p => p.price, products)
    )
  )
);
// 75000

문장의 해석은 오른쪽에서 왼쪽으로 읽어나가면 된다.

profile
console.log(noah(🍕 , 🍺)); // true
post-custom-banner

1개의 댓글

comment-user-thumbnail
2021년 12월 21일

20000원 미만 아닌가요??!

답글 달기