map, reduce, filter 서로 대체가 가능할까 (javascript)

자바스크립트 배열을 처리하는 메서드 map, reduce, filter

자바스크립트에서 배열의 요소에 접근하는 대표 메서드인 map, reduce, filter는 개발자라면 필수적으로 그리고 좀 더 상세히 알고 가면 좋을 것 같습니다.

각각의 특징에 대해 이야기하면 대부분은 아마도

  • map -> 모든 요소에 한 번씩 접근하기
  • reduce -> 모든 요소를 하나로 합치기
  • filter -> 모든 요소에서 원하는 것만 골라내기

정도의 개념을 갖고 있을 것 같습니다.

굳이 위 메서드가 아니라 forEach 문 등 다른 방식을 사용해도 같은 로직의 구현이 가능한데요.

그렇다면 위 메서드끼리도 서로 변경하여 같은 결과를 반환하도록 사용이 가능할까요?

각 메서드의 기능을 살펴보면서 알아보도록 하겠습니다.


1. map

먼저 메서드는 위와 같으며 *가 붙어있는 파라미터는 생략할 수 있습니다.

인덱스는 현재값의 인덱스, 배열은 map이 순회하는 배열 array를 의미합니다.

이제 map을 사용하는 가장 기본적인 코드를 확인해 보겠습니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const myArray = [10, 20, 30, 40, 50];
const newArray = myArray.map((value) => { return value });
console.log(newArray); // [10, 20, 30, 40, 50]
console.log(myArray===newArray); //false
const myArray = [10, 20, 30, 40, 50]; const newArray = myArray.map((value) => { return value }); console.log(newArray); // [10, 20, 30, 40, 50] console.log(myArray===newArray); //false
const myArray = [10, 20, 30, 40, 50];

const newArray = myArray.map((value) => { return value });

console.log(newArray);  // [10, 20, 30, 40, 50]
console.log(myArray===newArray); //false

map은 해당 배열 자체를 바꾸는 것이 아니므로 리턴값을 사용하기 위해서는 다른 변수에 넣어 주어야 합니다.

파라미터에서 index는 현재 접근한 요소의 index이며 array는 순회하는 배열 전체를 전달합니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const myArray = [10, 20, 30, 40, 50];
const newArray = myArray.map((value, index, array) => {
if(index%2){
return value-array[1];
}else{
return value-array[0];
}
});
console.log(newArray);
const myArray = [10, 20, 30, 40, 50]; const newArray = myArray.map((value, index, array) => { if(index%2){ return value-array[1]; }else{ return value-array[0]; } }); console.log(newArray);
const myArray = [10, 20, 30, 40, 50];

const newArray = myArray.map((value, index, array) => {
   if(index%2){
     return value-array[1];   
   }else{
     return value-array[0];
   }                              
});

console.log(newArray);

다음 코드는 자주 접하는 실수 중 하나로 코드의 동작 여부를 생각해 볼 필요가 있습니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const myData = {10, 20, 30, 40, 50};
const newData = myData.map((value) => {return value+1});
console.log(newData);
const myData = {10, 20, 30, 40, 50}; const newData = myData.map((value) => {return value+1}); console.log(newData);
const myData = {10, 20, 30, 40, 50};

const newData = myData.map((value) => {return value+1});

console.log(newData);

위 코드는 에러가 발생합니다.

바로 map의 특성 때문인데요. map은 배열에서 동작하는 메서드이며 객체 object에서는 동작하지 않습니다.

하지만 다음과 같이 배열 내부의 object는 접근 가능합니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const myData = [{name:'chamchi', age:3},{name:'ggongchi', age:2},{name:'myulchi', age:1}];
const newData = myData.map((value) => value.name );
console.log(newData); //['chamchi', 'ggongchi', 'myulchi']
const myData = [{name:'chamchi', age:3},{name:'ggongchi', age:2},{name:'myulchi', age:1}]; const newData = myData.map((value) => value.name ); console.log(newData); //['chamchi', 'ggongchi', 'myulchi']
const myData = [{name:'chamchi', age:3},{name:'ggongchi', age:2},{name:'myulchi', age:1}];

const newData = myData.map((value) => value.name );

console.log(newData); //['chamchi', 'ggongchi', 'myulchi']

그렇다면 map을 사용해 reduce나 filter 메서드와 같은 로직을 구현할 수 있을까요?

다음 코드를 통해 확인할 수 있을 것 같습니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const myArray = [1, 2, 3, 4, 5];
const newArray = myArray.map((value) => {
if(value%2){
return value;
}
});
console.log(newArray); //[1, undefined, 3, undefined, 5]
const myArray = [1, 2, 3, 4, 5]; const newArray = myArray.map((value) => { if(value%2){ return value; } }); console.log(newArray); //[1, undefined, 3, undefined, 5]
const myArray = [1, 2, 3, 4, 5];

const newArray = myArray.map((value) => {
   if(value%2){
     return value;   
   }                            
});

console.log(newArray); //[1, undefined, 3, undefined, 5]

홀수의 요소만 반환하고자 위와 같이 작성하더라도 map은 모든 요소를 반환합니다.

짝수 부분은 리턴값이 정의되지 않아 undefined로 반환된 것을 확인할 수 있습니다.

따라서 map은 reduce, filter의 기능은 구현할 수 없을 것 같습니다.


2. reduce

먼저 메서드는 위와 같으며 *가 붙어있는 파라미터는 생략할 수 있습니다.

누적값은 배열을 순회하면서 작업의 처리 결과를 누적하는 값으로 순회가 종료되면 최종 리턴값이 됩니다.

reduce의 예시로 모든 요소를 더하는 예시가 많다보니 용도는 전체 요소 더하거나 빼서 하나로 만들기라고

알고 있을 수 있지만 누적값 설정을 통해 다양한 방식으로 활용이 가능합니다.

인덱스는 현재값의 인덱스, 배열은 reduce가 순회하는 array 배열을 의미합니다.

마지막에 있는 시작값은 누적값의 처음 기본값을 전달합니다.

생략하면 0이 기본값이 됩니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const myArray = [10, 20, 30, 40, 50];
const newArray = myArray.reduce((acc, value) => { return acc + value });
console.log(newArray); // 150
const myArray = [10, 20, 30, 40, 50]; const newArray = myArray.reduce((acc, value) => { return acc + value }); console.log(newArray); // 150
const myArray = [10, 20, 30, 40, 50];
const newArray = myArray.reduce((acc, value) => { return acc + value });

console.log(newArray); // 150

시작값이 생략되었으므로 acc의 기본값은 0이 됩니다.

그럼 초기값을 설정한 샘플을 보겠습니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const myArray = [10, 20, 30, 40, 50];
const newArray = myArray.reduce((acc, value) => { return acc + value },100);
console.log(newArray); // 250
const myArray = [10, 20, 30, 40, 50]; const newArray = myArray.reduce((acc, value) => { return acc + value },100); console.log(newArray); // 250
const myArray = [10, 20, 30, 40, 50];
const newArray = myArray.reduce((acc, value) => { return acc + value },100);

console.log(newArray); // 250

이를 응용하여 초기값을 설정하면 다양한 결과를 만들 수 있습니다.

먼저 배열을 다른 배열로 복사하는 기능을 구현해 보겠습니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const myArray = [10, 20, 30, 40, 50];
const newArray = myArray.reduce((acc, value) => {
acc.push(value);
return acc;
},[]);
console.log(newArray); // [10, 20, 30, 40, 50]
const myArray = [10, 20, 30, 40, 50]; const newArray = myArray.reduce((acc, value) => { acc.push(value); return acc; },[]); console.log(newArray); // [10, 20, 30, 40, 50]
const myArray = [10, 20, 30, 40, 50];
const newArray = myArray.reduce((acc, value) => { 
     acc.push(value);
     return acc; 
 },[]);

console.log(newArray); // [10, 20, 30, 40, 50]

이것으로 map과 똑같은 로직의 구현이 가능합니다.

그렇다면 filter를 구현해 보겠습니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const myArray = [10, 20, 30, 40, 50];
const newArray = myArray.reduce((acc, value, index) => {
if(index%2){
acc.push(value);
}
return acc;
},[]);
console.log(newArray); // [20, 40]
const myArray = [10, 20, 30, 40, 50]; const newArray = myArray.reduce((acc, value, index) => { if(index%2){ acc.push(value); } return acc; },[]); console.log(newArray); // [20, 40]
const myArray = [10, 20, 30, 40, 50];
const newArray = myArray.reduce((acc, value, index) => { 
     if(index%2){
       acc.push(value);
     }
     return acc; 
 },[]);

console.log(newArray); // [20, 40]

코드를 통해 확인해보니 reduce는 초기값 설정을 통해 map이나 filter와 같은 로직의 구현이 가능합니다.


3. filter

filter는 말 그대로 배열의 요소를 필터링하여 조건이 참이 되는 요소만 반환합니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const myArray = [10, 20, 30, 40, 50];
const newArray = myArray.filter((value) => {
return value%20 === 0
});
console.log(newArray); // [20, 40]
const myArray = [10, 20, 30, 40, 50]; const newArray = myArray.filter((value) => { return value%20 === 0 }); console.log(newArray); // [20, 40]
const myArray = [10, 20, 30, 40, 50];

const newArray = myArray.filter((value) => { 
    return value%20 === 0
 });

console.log(newArray); // [20, 40]

filter는 필터링 기능만 갖고 있어 map이나 reduce의 로직을 만들긴 어려울 것 같습니다.



map과 filter는 용도가 조금 더 특정되어 있다보니 다른 메서드의 로직을 그대로 구현하기는 어렵지만 reduce는 초기값을 통해 다양한 로직의 구현이 가능해 다재다능한 메서드인 것 같습니다.