[JavaScript] map, filter, reduce / 반복 후 새로운 배열 반환
이전 게시글 에서 for, for...in, for...of, forEach에 대해 알아보았습니다. 앞 4개의 구문은 반복만 하고 끝입니다. 새로운 배열을 만들고 싶은 경우 빈 배열을 생성하여 추가해주어야 합니다. 만약 반복을 다 한 후 새로운 배열을 만들고 어떻게 할까요? 앞서 말한대로 빈 배열에 추가하여도 되지만 map, filter, reduce 를 사용해도 됩니다. 한번 알아봅시다. (아래 예시들은 설명을 위한 예시이므로 참고만 하시면 됩니다.)
map
arr.map(callback(currentValue[, index[, array]])[, thisArg])
map 함수는 위와 같이 생겼습니다. 배열에 사용할 수 있고 반복을 한 뒤 새로운 배열을 반환해줍니다. 간단한 예시로는 모든 배열 값에 *2를 하고 싶다 라고 하면 아래와 같이 구현할 수 있습니다.
const numbers = [1,2,3,4,5];
const doubleNumbers = numbers.map(item => item * 2);
console.log(doubleNumbers);
매우 간단하죠? 만약 위 과정을 for문으로 구현한다고 해봅시다.
const numbers = [1,2,3,4,5];
const doubleNumbers = [];
const doubleNumbersForEach = [];
for(let i = 0 ; i < numbers.length ; i++) {
doubleNumbers.push(numbers[i] * 2);
}
numbers.forEach(item => {
doubleNumbersForEach.push(item * 2);
})
console.log(doubleNumbers);
결과는 동일하지만 가독성의 차이는 분명히 있습니다. 그렇다면 이런 생각이 들 수 있습니다. 처음부터 map만 사용해서 구현하면 되지 않을까? 실제로 신입분들의 코드를 보면 map을 순수 반복만 하는 용도로 사용하는 분들이 있었습니다. map은 반복을 한 후 새로운 배열을 return 해줍니다. 만약 반복만 하는 것이었으면 for 를 사용하는 것이 맞습니다. 1가지 예를 들어봅시다.
const numbers = [1,2,3,4,5];
numbers.forEach(num => console.log(num))
numbers.map(num => console.log(num))
위 코드의 결과는 (거의)동일합니다. 그러나 map의 경우 용도에 맞게 사용하지 않았다고 볼 수 있습니다. 실제 결과 이미지를 보아도 마지막 undefined 5개의 배열이 출력되어 있습니다. 무엇이든 용도에 맞게 사용하는 습관을 길러야 합니다.
filter
arr.filter(callback(element[, index[, array]])[, thisArg])
filter는 이름에서 볼 수 있듯이 filtering을 하겠다 입니다. 배열을 반복하면서 특정 조건에 맞는 값만 알고 싶을 때 filter를 사용합니다. 바로 예제를 확인해봅시다. 아래 코드는 배열 중 홀수인 것만 골라내는 예제입니다.
const numbers = [1,2,3,4,5];
const oddNumbers = numbers.filter(num => num % 2)
console.log(oddNumbers);
이번에는 for문 예시를 안보여드려도 되겠죠? 분명히 위 코드보다 더 길고 복잡할 것입니다. 그렇다면 이런 생각을 할 수 있습니다. map이랑은 비슷한거 같은데 map으로 하면 안되나? 안됩니다. map은 전체 배열을 return 해주기 때문입니다. 배열 크기가 10이라면 return 되는 배열도 10개의 크기인 것이죠. 이해가 잘 안되시면 위 filter로 구현한 것을 map으로 구현해보시길 바랍니다. 직접 해보면 무슨 의미인 지 쉽게 파악할 수 있을 것입니다.
reduce
arr.reduce(callback[, initialValue])
위 reduce 함수를 더 쉽게 자주 사용하는 코드 형식으로 적어보겠습니다.
arr.reduce((acc, cur) => {
// ...
}, initialValue)
acc는 누적 값, cur는 현재 값입니다. reduce로 위 map, filter 함수를 모두 구현할 수 있고 2가지 일을 동시에 할 수도 있습니다. map, filter를 구현해보고 2가지 일을 동시에 하는 것도 한번 구현해보겠습니다. 우선 위에서 구현해본 map, filter와 동일한 동작을 하도록 구현해보겠습니다.
const numbers = [1,2,3,4,5];
const mapReduce = numbers.reduce((acc, cur) => {
return acc.concat(cur * 2);
}, []);
const filterReduce = numbers.reduce((acc, cur) => {
if(cur % 2) return acc.concat(cur);
return acc;
}, []);
console.log(mapReduce);
console.log(filterReduce);
위에서 본 결과와 동일합니다. 그럼 이번에는 2가지 일을 동시에 하도록 홀수만 filter한 후 해당 홀수 값에 2를 곱한 배열을 만들어봅시다. map, filter를 사용한 코드와 reduce를 사용한 코드를 비교해봅시다.
const numbers = [1,2,3,4,5];
const resultWithMapFilter = numbers.filter(num => num % 2).map(num => num * 2);
const resultWithReduce = numbers.reduce((acc, cur) => {
if(!Boolean(cur % 2)) return acc;
return acc.concat(cur * 2);
}, [])
console.log(resultWithMapFilter)
console.log(resultWithReduce)
위 결과는 동일합니다. 예시가 너무 쉬운 것이서 filter, map이 더 짧아보이긴 하는데 분명히 2가지 일을 같이할 때가 있을 것입니다. 그 경우를 대비해서 reduce도 공부하는 것이 좋습니다. 이것 뿐만이 아니라 속도에서 분명히 차이가 있을 것입니다. filter, map을 하게 되면 반복문을 2번 돌아야 합니다. 그러나 reduce의 경우 1번으로 해결할 수 있기 때문에 속도면에서도 더 빠릅니다.
◆ 간단정리
map, filter, reduce는 새로운 배열을 반환해준다.
상황에 따라 용도에 맞게 사용하면 된다.
reduce 1개로 map, filter를 동시에 할 수 있다.
◆ 참고자료
마지막
해당 내용은 틀릴 수도 있다는 것을 감안하여 봐주세요. 틀린 내용 및 오탈자 수정 요청 환영입니다.
'공유 > JavaScript, TypeScript' 카테고리의 다른 글
[JavaScript] callback과 callback 지옥 (0) | 2022.02.17 |
---|---|
[JavaScript] ISO 8601 시간 timestamp로 변환하기 (0) | 2022.02.15 |
[JavaScript] for, for in, for of, forEach 반복문 (0) | 2022.01.17 |
[JavaScript] var, let, const 차이, hosting, TDZ (0) | 2022.01.07 |
[JavaScript] call, apply, bind - this 친구들 (0) | 2022.01.05 |