공부/컴퓨터

자바스크립트 배열에서 forEach, filter, map, reduce 활용법

2019. 5. 11. 23:27
반응형

발단

요즘에 이것저것 한다고, javascript들을 좀 해 보고 있는데, 배열에 여러가지 작업을 쉽게 할 수 있어 좋은 함수들이 있어, 계속 쓰다가, 나중을 위해 정리 하려고 간단하게 기록.

배열을 loop 돌면서 무언가를 하고 싶다면 아래 함수들을 활용하자.

  • forEach : 한개씩 돌면서 무언가 하기, return value는 없음.
  • filter : 조건에 맞는것만 새로운 배열로. return value는 새 배열.
  • map : 한개씩 돌면서 연산한 결과를 새로운 배열로. return value는 새 배열
  • reduce : 한개씩 돌면서 이전 연산한 결과를 조합하여 사용하기. return value는 reuce 함수안에서 설정한 대로.
    • 무슨 말인지 이해가 어려울 수도 있는데... 알면 쉬움... ;;

간단한, forEach, filter, map 부터

  • 이해하기 쉽도록 되도록이면 쉬운 예제를 만들어 보았다.

forEach - 한개씩 돌면서 무언가 하기

["a", "b", "c"].forEach ( 
    function(x) {
        console.log(x);
    }
)
  • 결과 : 화면에 a, b, c 가 출력 된다.

filter - 배열에서 조건에 맞는것만 새로운 배열만들어 반환하기.

[ 1, 2, 3, 4, 5].filter(
    function(x) {
        return x % 2 == 0;
    }
)
  • 결과 : [ 2, 4 ] 배열이 반환된다.

filter + forEach - 조건에 맞는것만 배열로 만들어, 한개씩 돌면서 무언가 처리 하기

[ 1, 2, 3, 4, 5].filter(
    function(x) {
        return x % 2 == 0;
    }
).forEach ( 
    function(x) {
        console.log(x);
    }
)
  • 결과 : 화면에 2, 4 가 출력 된다.

map - 배열의 각 요소에 무슨짓한 결과를 새 배열로 반환

[ 1, 2, 3, 4, 5].map(
    function(x) {
        return x * 2;
    }
)
  • 결과 : [2, 4, 6, 8, 10] 배열이 반환된다.

map + forEach - 배열의 각 요소에 어떠한 연산을 하고, 그 결과를 하나씩 돌면서 무슨 짓을 하기

[ 1, 2, 3, 4, 5].map(
    function(x) {
        return x * 2;
    }
).forEach ( 
    function(x) {
        console.log(x);
    }
)
  • 결과 : 화면에 2, 4, 6, 8, 10 이 출력 된다.

filter + map + forEach - 배열에서 원하는 요소만 뽑아내고, 그 결과 배열에 어떠한 연산을 하고, 그 결과를 하나씩 돌면서 무슨짓을 하기

[ 1, 2, 3, 4, 5].filter(
    function(x) {
        return x % 2 == 0;
    }
).map(
    function(x) {
        return x * 2;
    }
).forEach ( 
    function(x) {
        console.log(x);
    }
)
  • 결과 : 화면에 4, 8 이 출력 된다.

조금 까다롭지만 활용성이 매우 좋은 reduce

  • reduce는 배열의 순환을 돌면서, 이전 결과를 활용하는 방식이다.
  • forEach, filter, map 과 같이 reduce도 내부에서 함수를 1개 받는데, 파라미터에 여러가지 정보가 들어온다.
  • 함수는 function ( ac, current, index, array ) 4개의 파라미터를 받는다.
    • ac : reduce 호출할때 넘긴 함수의 결과를 보관. 최초 호출될때는 reduce를 호출할때 두번째 넘김 파라미터의 값.
    • current : 배열의 0 번 부터 배열의 마지막까지 순차적으로 전달 됨
    • index : 현재 배열의 몇번째를 loop 돌고 있는지 알려 주는 값
    • array : reduce 함수를 호출한 배열.
  • 긴 설명은 설명이 잘 되어 있는 다른 사이트에서 찾도록 하자.
  • reduce 함수에서 위 4가지 파라미터를 활용하면, filter, map, forEach 를 모두 구현할 수 있다.
  • 즉, reduce 짱짱임.

reduce - 숫자가 들어 있는 배열의 합 구하기

[1, 2].reduce (
    function ( ac, current, index, array ) {
          // 최초 호출될때, ac는 reduce의 두번째 파라미터인 아래에서 넘긴 0 이고,, current는 배열의 0 번째인 1이 들어 있을 것이다.
          // 그러므로 최초 호출 될 때는 return 값이 0 + 1 이므로, 1이 return 될 것이다.
          // 두번째 호출 될 때는 ac는, 첫번째 호출 되었을때, return한 값인 1 값을 가지고, current는 배열의 1번째 2가 들어 있을 것이다.
          // 그리고 두번째 호출 될 때는 return 값이 1 + 2 인 3 이 될 것이다.
          // 더 이상 loop를 돌 아이템이 없으므로, 해당 함수의 리턴값의 3 이 될 것이다.
        ac = ac + current;
        return ac;
    }
,0); // reduce 함수의 두번째 파라미터인 0 은, 위 익명 함수의 ac에 최초 할당 된다.
  • 결과 : 3이 반환 될 것이다.

reduce - string 배열을 순환하면서 모든 배열 item을 1개의 string으로 합치기

[ "안녕", "하세요" ].reduce(
    function ( ac, current, index, array ) {
          // 최초 호출될때, ac는 reduce의 두번째 파라미터인 아래에서 넘긴 "" 값을 가지고, current는 배열의 0 번째 "안녕"의 값이 들어 있을 것이다.
          // 그러므로 최초 호출 될 때는 return 값이 "" + "안녕" 이므로, "안녕"이 return 될 것이다.
          // 두번째 호출 될 때는 ac는 첫번째 호출 되었을때, return한 값인 "안녕" 값을 가지고, current는 배열의 1번째 "하세요"가 들어 있을 것이다.
          // 그리고 두번째 호출 될 때는 return 값이 "안녕"+"하세요"가 될 것이다.
          // 더 이상 돌 item이 없으므로, 결과적으로 해당 함수의 return 값은 "안녕하세요"가 될 것이다.
        return ac + current; 
    }
, "" ) // reduce 함수의 두번째 파라미터인 "" 은, 위 익명 함수의 ac에 최초 할당 된다.
  • 결과 : "안녕하세요" 라는 값이 반환된다.

응? reduce 대신 forEach만 써도 되는거 아닌가?

  • 위 예제들을 사실, forEach만 사용해도 된다.

  • forEach를 사용해서 바로 위의 예제를 구현해 보자.

    let sumString = ""
    ["안녕", "하세요"].forEach(
        function (x) {
            sumString = sumString + x;
        }
    );
  • 위 예제와 주석이 제거된 reduce를 예제를 비교해 보자.

    let sumString = [ "안녕", "하세요" ].reduce(
        function ( ac, current, index, array ) {
           return ac + current; 
        }
    , "");
  • 결과는 동일하지만,

    • forEach는 배열의 loop 결과를 저장하기 위해서, sumString을 선언후 ""를 할당한 뒤 사용해야 했지만,
    • reduce는 배열의 loop 결과를 바로, sumString으로 할당 할 수 있다.

reduce - 배열에서 string type만 Set으로 만들기

[ 1, "안녕", "2", 3].reduce(
    function ( ac, current, index, array ) {
          // 최초 호출될때, ac는 reduce의 두번째 파라미터인 아래에서 넘긴 new Set() 값을 가지고, current는 배열의 0 번째 값인 1이 들어 있을 것이다.
          // 1은 string type이 아니므로, 그냥 ac를 반환한다.
          // 두번째 호출 될 때는 ac는 첫번째 호출 되었을때, return한 값인 new Set()이 그대로 들어 있을 것이고, current는 배열의 1번째 값인 "안녕"이 들어 있을 것이다.
          // "안녕"은 string type이므로, ac.add(current)를 이용해서 Set에 "안녕"을 넣는다. 그리고 ac를 반환한다.
          // 세번째 호출 될 때는 ac는 두번째 호출 되었을때, return한 값인 "안녕"이 들어 있는 Set이 들어 있을 것이고, current는 배열의 2번째 값인 "2"이 들어 있을 것이다.
          // "2"은 string type이므로, ac.add(current)를 이용해서 Set에 "2"을 넣는다. 이제 Set에는 "안녕"과 "2"가 들어 있다. 그리고 ac를 반환한다.
          // 네번째 호출 될 때는 ac는 세번째 호출 되었을때, return한 값인 "안녕"과 "2"가 들어 있는 Set이 들어 있을 것이고, current는 배열의 3번째 값인 3 이 들어 있을 것이다.
          // 3은 string type이 아니므로, "안녕"과 "2"가 들어 있는 ac를 반환한다.
          // 더 이상 돌 item이 없으므로, "안녕"과 "2"가 들어 있는 ac를 최종 반환하고 끝낸다.
        if ( typeof current == "string" ) {
            ac.add(current);
        }
        return ac;
    }
, new Set()); // reduce 함수의 두번째 파라미터인 new Set()은, 위 익명 함수의 ac 에 최초 할당된다.
  • 결과 : "안녕"과 "2"가 들어 있는 Set이 반환된다.

위 예제도, filter와 map 같은걸로 가능할 것 같은데?

  • 당근 가능하다. 위 예제는 Set을 반환했지만, filter + map과 reduce의 비교를 위해, 배열을 반환하도록 코드를 수정하겠다. 그리고 각 배열의 마지막에 "하세요"라는 문자를 추가하도록 하겠다.

  • 우선 filter + map 을 사용해서, 배열에서 string type만 array로 만들어 보자.

    [ 1, "안녕", "미안", 3].filter(
        function ( x ) {
           return typeof x == "string";
        }
    ).map(
        function ( x ) {
           return x + "하세요";
        }
    );
  • 그리고 reduce를 활용해, 배열에서 string type만 array로 만들어 보자..

    [ 1, "안녕", "미안", 3].reduce(
        function ( ac, current, index, array ) {
           if ( typeof current == "string" ) {
               ac.push(current + "하세요");
           }
           return ac;
        }
    , []);
  • 결과는 동일하지만,

    • filter와 map의 조합은 결과를 내기 위해서 배열의 loop를 두번 돌아야 하고, 정확하게는 item 을 6번 가지고 와야 한다. ( filter에서 4번, map에서 2번)
    • reduce는 배열을 한번의 loop를 돌면서 결과를 만들어 낼 수 있다. 정확하게는 item을 4번 가지고 오면 된다.

결론?

  • 처음에는 공부하기도 귀찮고 해서, 안 썼었는데...
  • 다른 강좌를 보다가 예제중에서 이걸 사용하는것들이 있어, 공부를 하게 됐다.
  • 지금은?
    • 거의 모든 배열의 loop는 이 함수들을 이용해서 처리하고 있다.
    • 익숙해 지니깐, 참 편하더라고...
반응형