ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Functional] map, filter, reduce
    programing/Language 2019. 7. 15. 18:27

    안녕하세요, Einere입니다.

    (ADblock을 꺼주시면 감사하겠습니다.)

     

    2019/06/25 - [programing/JavaScript] - [Functional] 평가와 일급, 고차함수

    2019/07/15 - [programing/JavaScript] - [Functional] 순회와 이터러블

    2019/07/15 - [programing/JavaScript] - [Functional] 제네레이터와 이터러블


    map

    const products = [
        {name: "볼펜", price: 500},
        {name: "샤프", price: 1000},
        {name: "자", price: 700},
        {name: "커터칼", price: 1500},
        {name: "수정테이프", price: 3000},
    ];
    
    // 함수와 이터레이터를 받아, 요소들을 순회하며, 특정 함수의 결과값을 배열에 채운 뒤 반환하는 함수
    const map = (func, iter) => {
        let ret = [];
        
        for(const e of iter) {
            ret.push(func(e));
        }
        
        return ret;
    };
    
    const names = map(item => item.name, products);
    console.log(names);
    // ["볼펜", "샤프", "자", "커터칼", "수정테이프"] 출력
    
    const prices = map(item => item.price, products);
    console.log(prices);
    // [500, 1000, 700, 1500, 3000] 출력

    위의 map함수는 이터러블 프로토콜을 준수하므로, 범용성 및 사용성이 뛰어나다.

     

     

     

    filter

    const filter = (f, iter) {
    	let arr = [];
        for(const e of iter) {
            if(f(e)) arr.push(e);
        }
        return arr;
    };
    
    // 상품 객체 배열에서, 15000원 이상 상품 이름을 얻고자 하는 경우
    const products = [
        {name:'반팔티', price:12000},
        {name:'긴팔티', price:15000},
        {name:'청바지', price:30000},
        {name:'야구모자', price:8000},
        {name:'캔버스화', price:25000}
    ];
    console.log(map(p => p.name, filter(p => p.price >= 15000, products)));
    // ['긴팔티', '청바지', '캔버스화'] 출력
    

    배열에서 특정 요소를 걸러내고 싶은 경우 사용.

     

     

    reduce

    const reduce = (f, acc, iter) => {
        if(!iter) {
            iter = acc[Symbol.iterator]();
            acc = iter.next().value;
        }
        for(const e of iter) {
            acc = f(acc, e);
        }
        return acc;
    };
    
    // 상품의 가격이 15000이상인 제품들의 총 합을 구하고 싶은 경우
    const products = [
        {name:'반팔티', price:12000},
        {name:'긴팔티', price:15000},
        {name:'청바지', price:30000},
        {name:'야구모자', price:8000},
        {name:'캔버스화', price:25000}
    ];
    const add = (a, b) => a + b;
    console.log(
        reduce(add, 
            map(p => p.price, 
                filter(p => p.price >= 15000, products)
            )
        )
    );
    // 70000 출력
    

    배열에서 특정 연산을 수행하여 하나의 값을 얻고자 하는 경우 사용. (누산, 합계 등등..)

    비동기 상황을 고려하면 다음과 같이 수정할 수 있습니다.

     

    const reduce = curry(async (f, acc, iter) => {
        if (!iter) {
            iter = acc[Symbol.iterator]();
            acc = await iter.next().value;
        }
        for (const e of iter) {
            acc = await f(acc, e);
        }
        return acc;
    });
    
    go(Promise.resolve(1),
        v => v + 10,
        v => new Promise((res, rej) => {
            setTimeout(() => {
                res(v + 100);
            }, 2000);
        }),
        v => Promise.reject('error~~'),
        v => v + 1000,
        console.log
    ).catch(result => console.log(result));
    
    /* 출력
    error~~
    */

    go함수는 reduce를 사용하므로, 결과 또한 promise가 됩니다. 따라서, catch를 체이닝하여 에러 핸들링을 할 수 있습니다.

     

     

    참고

    마이클 포거스, 『함수형 자바스크립트 : 새롭고 올바른 자바스크립트 프로그래밍 기법』, 한빛미디어(2014).

    유인동, 인프런 - 함수형 프로그래밍과 JavaScript ES6+

    댓글

Designed by black7375.