본문 바로가기

Languages/JavaScript

[JavaScript] map, reduce 배열 메서드

728x90

 

   목차 

1. map 메서드
- 개요
- 문법
- 자세한 설명
- 예제

2. reduce 메서드
- 개요
- 문법
- 예제

3. map을 reduce로 바꿔보기

 

 

 

React를 배울 때 많이 쓰일 메서드인 map, reduce 메서드를 알아보자! 

 


 

 

 Array.prototype.map() 

 

map() 메서드배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환한다.

 

- 배열 각각의 element들을  다 바꾸고 새로운 array를 가지고 싶을때
- map은 매개변수 안에 함수를 넣을 수 있도록 해줌
- 이 함수는 배열의 모든 item에 대해 실행됨
- 이 함수에서 무엇을 return하든간에 그 return한 값이 새로운 array에 들어가 있게 됨
- 즉, map은 하나의 배열에 있는 item을 내가 원하는 무엇이든지로 바꿔주는 역할을 하고, 그건 결국 새로운 배열로 return해줌
- 예전 배열을 가져와서 변형해주는 것

 

const array1 = [1, 4, 9, 16]; 


const map1 = array1.map(x => x * 2)

console.log(map1); // [2, 8, 18, 32]

 

array1이라는 배열이 있으면,
map 메서드를 통해 요소 각각 [1, 4, 9, 16]에 2배를 해주는 함수를 호출해서 새로운 배열 [2, 8, 18, 32]을 반환하게 한다.

 

 

 

 문법 

 

 arr.map(callback(currentValue[, index[, array]])[, thisArg])

 

callback 새로운 배열 요소를 생성하는 함수. 세 가지 인수(currentValue, index, array)를 가진다.
currentValue 처리할 현재 요소
index 처리할 현재 요소의 인덱스 (선택사항)
array map()을 호출할 배열 (선택사항)
thisArg callback을 실행할 때 this로 사용되는 값 (선택사항)
반환값 배열의 각 요소에 대해 실행한 callback의 결과를 모은 새로운 배열

 

 

 

 자세한 설명 

 

- map은 callback 함수를 각각의 요소에 대해 한번씩 순서대로 불러 그 함수의 반환값으로 새로운 배열을 만든다.

- callback 함수는 (undefined도 포함해서) 배열 값이 들어있는 인덱스에 대해서만 호출된다. 

- 즉, 값이 삭제되거나 아직 값이 할당/정의되지 않은 인덱스에 대해서는 호출되지 않는다.

- callback 함수는 호출될 때 대상 요소의 값, 그 요소의 인덱스, 그리고 map을 호출한 원본 배열 3개의 인수를 전달받는다.

- thisArg 매개변수가 map에 전달된 경우 callback 함수의 this값으로 사용되고, 그 외의 경우 undefined값이 this 값으로 사용된다.

- callback 함수에서 최종적으로 볼 수 있는 this 값은 함수 내 this를 정하는 일반적인 규칙에 따라 결정된다.

- map이 처리할 요소의 범위는 첫 callback을 호출하기 전에 정해진다. map이 시작한 이후 배열에 추가되는 요소들은 callback을 호출하지 않는다.

- 배열에 존재하는 요소들의 값이 바뀐 경우 map이 방문하는 시점의 값이 callback에 전달된다. map이 시작되고, 방문하기 전에 삭제된 요소들은 방문하지 않는다.

- map을 호출한 배열의 중간이 비어있는 경우, 결과 배열 또한 동일한 인덱스를 빈 값으로 유지한다. 

 

 

 

 map 예제 

 

 

 map 예제 1 (배열에 들어있는 문자열을 대문자로 바꿔서 새로운 배열을 만들기) 

['good', 'best'].map( (item) ⇒ item.toUpperCase( ) )
// (2) ['GOOD', 'BEST']

 

 

 

 map 예제 2 (배열에 안에 있는 객체에서 키값을 추출해서 새로운 배열을 만들기) 

const people =[ 
{ 
name: '짱구', 
age: 6, 
job: '유치원생', 
}, 
{
name: '봉미선', 
age: 30, 
job: '가정주부', 
}, 
{ 
name: '채성아',
age: 24, 
job: '교사', 
} 
];


let jobs = people.map((item)=>{
return item.job  
})

console.log(jobs); // (3) ['유치원생', '가정주부', '교사']

여기서 item은 각각 3개의 객체를 뜻한다. 각 객체의 job을 수집해서 새로운 배열을 만드는 것이다.

 

const people =[ 
{ 
name: '짱구', 
age: 6, 
job: '유치원생', 
}, 
{
name: '봉미선', 
age: 30, 
job: '가정주부', 
}, 
{ 
name: '채성아',
age: 24, 
job: '교사', 
} 
];

let jobs = people.map((item)=>{
return `<li>${item.name}</li>`
})

console.log(jobs); // (3) ['<li>짱구</li>', '<li>봉미선</li>', '<li>채성아</li>']

 각 객체의 name을 수집해서 새로운 배열을 만드는 것이다.

 

 

 

 map 예제 3 (배열 속 객체를 재구성 하기 - 예제 설명을 위해 var 사용) 

var kvArray = [{key:1, value:10},
               {key:2, value:20},
               {key:3, value: 30}];

var reformattedArray = kvArray.map(function(obj){
   var rObj = {};
   rObj[obj.key] = obj.value;
   return rObj;
});

console.log(reformattedArray) // (3) [{1:10}, {2:20}, {3:30}]
- reformattedArray는 map을 통해 만들어질 새로운 배열을 뜻한다.
- callback 함수에 들어간 매개변수 obj는 배열 kvArray에서 각각의 객체 3개를 뜻한다.
- rObj[obj.key] = obj.value; 는 빈 객체인 rObj에다가 kvArray의 각각의 객체에서 빼낸 프로퍼티를 추가하는 것이다.

 

*참고) 대괄호 표기법으로 객체의 프로퍼티 추가하는 법


 

 

 map 예제 4 (배열에 들어있는 숫자들의 제곱근을 구하여 새로운 배열을 만들기) 

const numbers = [1, 4, 9];
const roots = numbers.map(Math.sqrt);

console.log(roots); // (3) [1, 2, 3]

// numbers는 그대로 [1, 4, 9]

 

 


 

 

 Array.prototype.reduce() 

 

reduce() 메서드배열의 각 요소에 대해 주어진 리듀서 (reducer) 함수를 실행하고, 하나의 결과값을 반환한다.

- reduce는 줄여서 작업한다
- 배열을 받아서 새로운 무언가(문자, 숫자, 배열, 객체)를 만들때 씀
- 초기값으로 무언가를 정한다.
- map (배열을 받아 새로운 배열을 반환)이 있어서 reduce에서는 배열을 잘 안씀
- {…spread}가 있어서 객체도 잘 안씀

 

 

 

 

 문법 

 

arr.reduce(callback(accumulator, currentValue, index, array), initialValue)

풀어서 설명하면 아래 코드와 같다.

const numbers = [1, 2, 3, 4];

numbers.reduce((누산값, 현재요소값, 현재요소의index, 현재배열) => {
  return 다음누산값;
}, 초기누산값);

 

arr 순회하고자하는 배열
callback 배열의 각 요소에 대해 실행할 함수. 네가지 인수(accumulator,  currentValue, currentIndex, array) 
accumulator 누적 되는 값 
- callback 함수의 반환값을 누적한다.
- initialValue(초기값)을 설정한 경우 callback 최초 호출 시 initialValue로 초기화
-  initialValue가 없는 경우 arr의 0번째 인덱스 값으로 초기화
currentValue 처리할 현재 요소 
currentIndex 현재 배열 요소의 index (선택 사항)
- initialValue를 제공한 경우 0, 아니면 1부터 시작한다.
array reduce()를 호출한 배열 (선택 사항)
initialValue callback의 최초 호출 시 accumulator 초기 값 (선택 사항)
빈 배열에서 초기값 없이 reduce()를 호출하면 오류가 발생한다.
반환값 누적 계산의 결과 값

 

 

 

 reduce 예제 

 

 

 reduce 예제 1 (기본 원리 쉽게 알아보기- 오브젝트 배열에서 원하는 항목의 값만 더하기) 

const people =[ 
{ 
name: '짱구', 
age: 6, 
job: '유치원생', 
}, 
{
name: '봉미선', 
age: 30, 
job: '가정주부', 
}, 
{ 
name: '채성아',
age: 24, 
job: '교사', 
} 
];

people.reduce((acc,cur)=>{
return acc+cur.age
}, 0) 

// 60
< 코드 설명 >

- 초기값 0이 acc에 등록됨.  acc=0

- 0이 밑에 줄의 acc로 들어감
- cur에는 6이 들어옴 (cur은 순환하는 무언가 )
- 0+6 (acc+cur) 하면 6됨
- 6이 acc로 올라감 (그냥 그렇게 생겨먹음. 누적값이라/한번돌면누적하고 또 한번돌면 누적하고)
- cur에 30이 들어옴
- 6+30 (acc+cur) 하면 36됨
- 36이 acc로 올라감
- cur에 24가 들어옴
- 36+24 (acc+cur) 하면 60됨 → 결국 최종값은 60
- 60를 반환하는게 reduce의 목적임
- reduce는 새로운 무언가를 “만들 때” 쓰니까 결과를 내뱉어줘야함 (return필요) (참고로 forEach는 내뱉지않음) 

 

 

 

 reduce 예제 2 (콘솔 출력으로 동작원리 자세히 알아보기) 

const numbers = [1, 2, 3, 4];

const sum = numbers.reduce((acc, cur, i) => {
  console.log(`${i}번째 콜백함수`)
  console.log(`acc: ${acc}`);
  console.log(`cur: ${cur}`);

  return cur + acc;
}, 0);

console.log(`-----------`);
console.log(`sum: ${sum}`);

 

 

 

 

 reduce 예제 3 (초기값이 있을 경우 값이 어떻게 전달되는 지 알아보기) 

const arr = [1, 2, 3, 4];

function func(accumulator, currentValue, currentIndex, array) {
  console.log("acc: " + accumulator + ", cur: " + currentValue
    + ", curIndex: " + currentIndex + ", array: " + array);
  return accumulator + currentValue;
}

const initialValue = 0;
const sumWithInitial = arr.reduce(func, initialValue);

// 0 + 1 + 2 + 3 + 4
console.log(sumWithInitial);

 

첫번째줄 함수계산에서 acc에는 초기값인 0이 들어가고, cur에는 배열의 index 0번째 값인 1이 들어간다.

 

 

 

 reduce 예제 4 (초기값이 없을 경우 값이 어떻게 전달되는 지 알아보기) 

const arr = [1, 2, 3, 4];

function func(accumulator, currentValue, currentIndex, array) {
  console.log("acc: " + accumulator + ", cur: " + currentValue
    + ", curIndex: " + currentIndex + ", array: " + array);
  return accumulator + currentValue;
}

const sumWithInitial = arr.reduce(func);

// 1 + 2 + 3 + 4
console.log(sumWithInitial);

 

첫번째줄 함수계산에서 acc에는 배열의 index 0번째 값인 1이 들어가고, cur에는 배열의 index 1번째 값인 2가 들어간다.

 

 

 

 reduce 예제 5 (배열 numbers를 입력으로 받아 각 요소를 2배로 만들어 새로운 배열을 반환하기

function solution(numbers) {
    return numbers.reduce((a, b) => [...a, b * 2], []);
}

 

< 코드 설명 > 

ex. numbers = [1, 2, 3, 4, 5]

1. reduce 함수를 사용하여 배열 numbers를 반복하는데, 초기값으로 빈 배열 []을 사용한다.
2. 첫 번째 요소 1이 현재 요소 b로 전달된다. 현재의 누적값 a는 초기값인 빈 배열 []이다.
3. 현재 요소 b를 2배하여 1 * 2는 2가 된다. 이 값 2가 현재의 누적값 a에 추가되어 [2]가 된다.
4 .두 번째 요소 2가 현재 요소 b로 전달된다. 현재의 누적값 a는 [2]이다.
5. 현재 요소 b를 2배하여 2 * 2는 4가 된다. 이 값 4가 현재의 누적값 a에 추가되어 [2, 4]가 된다.
6. 세 번째 요소 3이 현재 요소 b로 전달된다. 현재의 누적값 a는 [2, 4]이다.
7. 현재 요소 b를 2배하여 3 * 2는 6이 된다. 이 값 6이 현재의 누적값 a에 추가되어 [2, 4, 6]이 된다.
8. 최종적으로는 [2, 4, 6]이 반환되어 각 요소가 2배가 된 새로운 배열이 만들어진다.

 

 

 

 


 

 

 map을 reduce로 바꿔보기 

 

 

 map으로 만든 홀수 짝수 예제 

const oneTwoThree = [1, 2, 3];

let result = oneTwoThree.map((v) => {
  if (v % 2) {
    return '홀수';
  }
  return '짝수';
});
result; // ['홀수', '짝수', '홀수']
< 코드 설명 >

배열 [1, 2, 3] 에서 1, 2, 3이 차례로 인수로 들어가게될 것이다.  

- map 함수의 매개변수 v에 1이 들어온다.
- if 절을 만났는데 조건이 (v % 2) 이므로, (1 % 2) 즉, 1을  2를 나눴을때 나머지 값이 1이므로 true가 돼서 if절이 실행된다.
- return 값으로 '홀수'를 반환하고, 그것이 새로운 배열에 들어간다. // ['홀수']

- map 함수의 매개변수 v에 2이 들어온다.
- if 절을 만났는데 조건이 (v % 2) 이므로, (2 % 2) 즉, 2를  2를 나눴을때 나머지 값이 0이므로 false가 돼서 if절이 실행되지않고 다음 줄로 넘어간다.
- return 값으로 '짝수'를 반환하고, 그것이 새로운 배열에 추가된다. // ['홀수', '짝수']

- map 함수의 매개변수 v에 3이 들어온다.
- if 절을 만났는데 조건이 (v % 2) 이므로, (3 % 2) 즉, 3를  2를 나눴을때 나머지 값이 1이므로 true가 돼서 if절이 실행된다.
- return 값으로 '홀수'를 반환하고, 그것이 새로운 배열에 추가된다. // ['홀수', '짝수', '홀수']

 

 

 위의 map예시를 reduce로 바꿔보자 

const oneTwoThree = [1, 2, 3];

let result = oneTwoThree.reduce((acc, cur) => {
  acc.push(cur % 2 ? '홀수' : '짝수');
  return acc;
}, []);
result; // ['홀수', '짝수', '홀수']
< 코드 설명 >

- 초기값이 빈배열로 acc에 등록됨.  acc=[ ]- [ ]이 매개변수인 acc로 들어감- cur에 1이 들어옴. ( cur % 2 ) 이므로, ( 1 % 2 ) 즉, 1을 2로 나눴을 떄 나머지 값이 1이므로 true가 돼서 '홀수'가 return된다. -  acc.push('홀수') 이므로 빈배열[ ]인 acc에 '홀수'가 추가된다.  // ['홀수']

- ['홀수']가 acc로 올라감 - cur에 2가 들어옴. ( cur % 2 ) 이므로, ( 2 % 2 ) 즉, 2을 2로 나눴을 떄 나머지 값이 0이므로 false가 돼서 '짝수'가 return된다. -  acc.push('짝수') 이므로 ['홀수']인 acc에 '짝수'가 추가된다.  // ['홀수', '짝수']

- ['홀수', '짝수']가 acc로 올라감 - cur에 3가 들어옴. ( cur % 2 ) 이므로, ( 3 % 2 ) 즉, 3을 2로 나눴을 떄 나머지 값이 1이므로 true가 돼서 '홀수'가 return된다. -  acc.push('홀수') 이므로 ['홀수', '짝수']인 acc에 '홀수'가 추가된다.  // ['홀수', '짝수', '홀수']

- 최종 결과 값(result)으로 ['홀수', '짝수', '홀수'] 가 나오게된다.

 

 

더 많은 다른 배열 메서드는  https://dev-ini.tistory.com/51 를 참고해주세요!

 

 

 

참고 자료

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

728x90