[JS] 고차함수 정복하기 2편: 예제로 알아보는 핵심 배열고차함수(반복메소드)

Jeongwon Seo·2021년 8월 14일
0

JS/Node

목록 보기
5/16

0. 뭐? 배열에 내장 고차함수가 있다고?

네 사실입니다. 배열의 메소드에는 함수를 인자로 받으면서 함수를 리턴해주는 메소드가 몇개 있습니다. 그중에서 주로 쓰는 것은 Array.map, Array.filter, Array.reduce입니다.

1. Array.map메소드

Array.map은 각 엘리먼트와 반복해서 접촉하면서 인자로 오는 함수를 실행해주는 메소드입니다.
만약에 [1,2,3,4,5] 배열이 있다고 가정했을 때, 각각의 엘리먼트의 값에 1을 더한 배열을 출력하고싶다면, 가장 먼저 떠오르는 반복문을 사용해서 코드를 작성할 것입니다.

const arr = [1,2,3,4,5];
const result = []
for (let i=0;i<arr.length;i++) {
  result.push(arr[i]+1)
}
console.log(result); // [2,3,4,5,6]

하지만 고차함수 map(과 화살표함수 스킬)을 이용하면 간단하게 코드를 작성할 수 있습니다.

const arr=[1,2,3,4,5];
console.log(arr.map(el => el+1)) // [2,3,4,5,6]
//위 코드는 다음과 같다.
console.log(arr.map(function (el) {
  return el + 1
})); // [2,3,4,5,6]

참 쉽죠잉?

2. Array.filter 메소드

Array.filter 메소드는 각 엘리먼트와 반복해서 접촉하면서 인자로 오는 함수의 조건에 만족하는 엘리먼트만 리턴해주는 메소드입니다.
만약에 [1,2,3,4,5] 배열 중에서 짝수만 골라내고 싶다면 다음과 같이 작성하면 되겠습니다.

const arr = [1,2,3,4,5];
console.log(arr.filter(el => el % 2 === 0)); // [2,4]

3. Array.reduce 메소드

Array.reduce는 각각의 엘리먼트와 접촉한 다음에 인자로 오는 함수를 실행시키면서 값을 누적시키는 메소드입니다.
예를 들어서 [1,2,3,4,5] 배열에서 배열의 엘리먼트들의 합을 구하고 싶다면 다음과 같이 작성하면 됩니다.

const arr = [1,2,3,4,5];
console.log(arr.reduce((prev, cum) => prev + cum, 0)); // 15

여기서 prev는 한 단계가 끝나기 전에 누적하기 전의 값입니다. 만약에 위의 경우(,0)처럼 초기값을 지정해주면 0이 처음에 prev로 들어가게 됩니다. 그다음에 초기값이 지정이 되어있으므로 cum(누적시키고자 하는 값)은 0번째 인덱스의 엘리먼트가 들어가게 됩니다. 그러면 일단은 결과가 1이 리턴되게 됩니다. 그다음에 그 리턴된 값을 다시 prev로 넣습니다. 그다음에는 0번째 인덱스 다음인 1번째 인덱스 값(2)을 누적시켜서 덧셈함수를 실행합니다. 그러면 3이 되겠죠? 이러한 반복을 배열의 엘리먼트가 모두 반영될때까지 반복합니다. 그래서 결과가 15가 되는 것입니다.

3-1. Array.reduce의 다른 예시

그런데 Array.reduce는 숫자만 누적할 수만 있는 것은 아닙니다. 객체, 배열도 누적할 수 있습니다.

  • 배열의 특정 요소의 키만 추출하기
function joinName(resultStr, user) {
  resultStr = resultStr + user.name + ', ';
  return resultStr;
}
const users = [
  { name: 'Lee Jung-hoo', age: 22 },
  { name: 'Kim Hye-seong', age: 22 },
  { name: 'Park Hae-min', age: 31 },
  { name: 'Kim Hyun-soo', age: 33 },
];
users.reduce(joinName, ''); // "Lee Jung-hoo, Kim Hye-seong, Park Hae-min, KIM Hyun-soo, "
  • 배열을 객체로 바꾸기
function makeAddressBook(addressBook, user) {
  let firstLetter = user.name[0];

  if(firstLetter in addressBook) {
    addressBook[firstLetter].push(user);
  } else {
    addressBook[firstLetter] = [];
    addressBook[firstLetter].push(user);
  }

  return addressBook;
}

const users = [
  { name: 'Lee Jung-hoo', age: 22 },
  { name: 'Kim Hye-seong', age: 22 },
  { name: 'Park Hae-min', age: 31 },
  { name: 'Kim Hyun-soo', age: 33 },
];

users.reduce(makeAddressBook, {});
  1. 종합예제
  • 문제
    야구선수의 정보가 담긴 객체를 요소로 갖는 배열을 입력받아 아래 조건에 맞게 변형된 배열을 리턴해야 한다고 가정합니다.
    (모든 자료는 스탯티즈에서 따왔습니다. wrc 속성에는 실제로는 wrc+가 들어갔습니다. 김현수 2008년 wrc+ 176.5 무엇...)

키움 선수의 정보만 리턴해야 됩니다.
'wrc' 속성값은 평균값(number 타입)으로 바꿉니다.
입력
인자 1 : players
객체를 요소로 갖는 배열
arr[i]는 'name', 'team' 등의 속성을 갖는 객체
'wrcs' 속성은 number 타입을 요소로 갖는 배열
'wrcs' 속성이 빈 배열인 경우는 없다고 가정합니다.
입출력 예시

let playerList = [
  {
    name: 'Lee Jung-hoo',
    team: 'Kiwoom Heroes',
    wrcs: [112.1, 127.4, 135.4, 143.6, 156.8],
  },
  {
    name: 'Kim Hye-seong',
    team: 'Kiwoom Heroes',
    wrcs: [75.0, 88.5, 99.4, 99.7],
  },
  {
    name: 'Park Hae-min',
    team: 'Samsung Lions',
    wrcs: [85.6, 99.1, 77.0, 97.8, 110.2],
  },
  {
    name: 'Kim Hyun-soo',
    team: 'LG Twins',
    wrcs: [163.2, 155.2, 126.1, 148.4, 134.3],
  },
];
let output = playerReports(playerList);
console.log(output); // -->
[
  { name: 'Lee Jung-hoo', team: 'Kiwoon Heroes', wrc: 135.18 },
  { name: 'Kim Hye-seong', team: 'Kiwoon Heroes', wrc: 90.65 },
];

이 문제를 풀기 위한 수도코드는 다음과 같습니다.

  1. 우선 filteredArr 배열을 선언합니다. 그리고 전체 배열 중에서 키움소속인 것만 거르고 이를 filteredArr에 할당합니다
  2. filteredArr 배열을 매핑합니다.
  3. sumOfWrc 변수를 선언하고, 각각의 배열에서 wrc의 합을 reduce를 써서 구한 값을 할당합니다.
  4. AvgOfWrc 변수를 선언하고 sumOfWrc에 각각의 변수길이만큼 나눠줍니다.
  5. wrc에 AvgOfWrc값을 덮어씁니다.
  6. 그다음에 매핑한 함수의 결과를 리턴합니다.

위의 수도코드를 바탕으로 코딩을 하면 다음과 같습니다.

function playerReports(players) {
  // TODO: 여기에 코드를 작성합니다.
  // 키움 선수만 추립니다.
  // 키움 선수의 wrc의 합을 구해서 각각의 length로 나눠줍니다.
  let filteredplayers = players.filter(el => el.team === 'Kiwoom Heroes')
  return filteredplayers.map((element) => {
    let sumOfWrc = element.wrcs.reduce((acc,cur) => acc+cur)
    let meanOfWrc = Number((sumOfWrc/element.wrcs.length).toFixed(2));
    element.wrcs = meanOfWrc
    return element;
  })

}
profile
피트는 구덩이라는 뜻이다 구덩이를 파다보면 좋은 것이 나오겠지 (아싸 벡스룬)

0개의 댓글