forEach, filter, map, reduce

qwe8851·2022년 6월 12일
0

JS기초

목록 보기
12/17

배열을 loop돌면서 무언가 하고싶을때 for loop문보다 간편하게 쓸 수 있는 함수들을 정리해보려고 합니다.

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]
    }
);

응용1) map+forEach

: 배열의 각 요소에 어떠한 연산을 하고, 그 결과를 하나씩 돌면서 무언가 처리하기

[ 1, 2, 3, 4, 5].map(
    function(x) {
        return x * 2;
    }
).forEach ( 
    function(x) {
        console.log(x);	//2, 4, 6, 8, 10
    }
);

응용2) 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도 내부에서 함수를 한 개 받는데, 파라미터에 여러가지 정보가 들어옴.
  • 함수는 function(ac, current, index, array) 4개의 파라미터를 받음.
    • ac : reduce 호출할 때 넘긴 함수의 결과를 보관. 최초 호출될때는 reduce를 호출할때 두번째 넘김 파라미터의 값.
    • current : 배열의 0번째부터 배열의 마지막까지 순차적으로 전달 됨.
    • index : 현재 배열의 몇 번째를 loop돌고 있는지 알려주는 값
    • array : reduce함수를 호출한 배열.
  • reduce 함수에서 위 4가지 파라미터를 잘 활용하면 filter, map, forEach를 모두 구현할 수 있다.

응용1) 숫자가 들어있는배열의 합 구하기

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

응용2) string배열을 순환하면서 모든 배열 item을 1개의 string으로 합치기

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

Q. reduce대신 forEach만 써도 되지 않을까?

위 예제들은 forEach만 써도 된다.

forEach를 사용해서 위의 예제를 구현해보자

let sumString = "";
["안녕", "하세요"].forEach(
  function(x){
    sumString = sumString + X;
  }
);

결과는 동일하지만,

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

응용3) 배열에서 string type만 Set으로 만들기

[1, "안녕", "2", 3].reduce(
  funtionc(ac, current, index, array){
  // [첫 번째 loop]
  //최초 호출될 때, ac는 reduce의 두 번째 파라미터인 아래에서 넘긴 new Set()을 가지고, current는 0번째 배열값인 1이 들어있음.
  // 1은 string type이 아니므로, 그냥 ac를 반환한다.

  // [두 번째 loop]
  // 두번째 호출될 때 ac는 첫번째 호출되었을때 return한 값인 new Set()이 그대로 들어있을 것이고, current는 1번째 배열값인 "안녕"이 들어있을 것이다.
  // "안녕"은 string type이므로, ac.add(current)를 이용해서 Set안에 "안녕"넣고 ac를 반환한다.
  
  // [세 번째 loop]
  // 세 번째 호출될 때 ac는 두번째 호출되었을때 return한 값인 "안녕"이 들어있는 Set이 들어있을 것이고, current는 2번째 배열값인 "2"가 들어있을 것이다.
  // "2"은 string type이므로, ac.add(current)를 이용해서 Set안에 "2"넣는다
  // 그럼 이제 Set안에는 "안녕"과 "2"가 들어있고 ac를 반환한다.
  
  // [네 번째 loop]
  // 네 번째 호출될 때 ac는 세 번째 호출되었을때 return한 값인 "안녕"과 "2"가 들어있는 Set이 들어있을 것이고, current는 3번째 배열값인 3이 들어있을 것이다.
  // "3"은 string type이 아니므로, 그냥 "안녕"과 "2"가 들어있는 ac를 반환한다.

  // 더 이상 loop를 돌 아이템이 없으므로, "안녕"과 "2"가 들어있는 ac가 최종 반환될 것이다.
  if(typeof current == "string"){
  	ac.add(current);
  }
  return ac;
}, new Set()); //reduce함수의 두 번재 파라미터인 new Set()은, 위 익명 함수의 ac에 최초 할당됨

Q. 위 에제도 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번만 가지고 오면 됩니다.





# Summary

  • forEach : 한개씩 돌면서 무언가 하기, return value는 없음.
  • filter : 조건에 맞는것만 새로운 배열로. return value는 새 배열.
  • map : 한개씩 돌면서 연산한 결과를 새로운 배열로. return value는 새 배열
  • reduce : 한개씩 돌면서 이전 연산한 결과를 조합하여 사용하기. return value는 reuce 함수안에서 설정한 대로.

+) Sort()와 filter()의 차이

  • sort는 원본을 변형하게 되고
  • filter은 원본 변형이 되지 않기 때문에
    변수에 넣어서 사용해야 한다.

0개의 댓글