[코딩노트] S2 Unit 1 - javascript 고차함수

나현·2022년 9월 20일
0

코딩노트

목록 보기
6/11
post-thumbnail

💡 이 포스트에는 S2 Unit 1. javascript 고차함수 - map, filter, reduce 등과 관련된 코딩과제를 하고 몰랐던 점이나 부족했던 점을 정리했다!
(누군가에게는 너무 쉬워 하품이 나올 수 있습니다.🥲)

코딩노트 정리하기

이번에는 고차함수 중 콜백함수의 사용법과 내장된 고차함수 메서드인 map, filter, reduce를 실습할 수 있는 코딩문제를 풀었다.
문제를 풀며 막혔던 내용, 새로 발견한 내용 등을 정리해 보았다.

1. 임의의 값 중에서 어떤 값n의 순서 구하기

핵심 : 어떤 값 n보다 작은 값들의 개수에 1을 더하면 n의 순서가 된다.
핵심 : 배열이면, 어떤 값 n보다 작은 값들의 개수가 n의 순서가 된다.
위 핵심의 원리로 보다 작은 값만 판별할 수 있다면 배열을 정렬하지 않고도 어떤 값 n의 순서를 구할 수 있다.
map을 사용하는 방법이 있고, reduce를 사용하는 방법이 있다.

let arr=[3,1,4]; //
let n=2;
//방법1 map : index가 따로 필요
function code01(n){
  let index=0; //순서
  arr.map((el)=>{
    if(el<n) index+=1;
  });
  return index;
}
//방법2 reduce
function code02(n){
  return arr.filter((el)=>{
    return el < n;
  }).length; //filter가 리턴하는 값의 길이를 리턴
}

code01(n); //
code02(n); //

2. truthy 값, falsy 값의 활용

핵심 : 조건문 사용시 if(n!==0)과 if(n)은 같다.
이 내용은 고차함수와는 큰 연관이 없지만 코딩문제를 풀 때 자주 나오기도 했고, 놓치면 안될 내용이라 작성했다.
if(n)은 값의 존재여부를 떠나 0이 아닐 때도 활용 가능하다. 0은 falsy값이지만 0이 아닌 숫자는 truthy값이기 때문이다.
이 원리를 이용하여 if(n%2!==0)와 if(n%2)도 같은 의미라 할 수 있다.

3. 배열의 평균 구하기

핵심 : 총합은 reduce로 간편하게 구할 수 있다.
어떤 배열의 총합을 구해 배열의 길이로 나누면 된다.
빈 배열의 예외가 있을 경우 먼저 조건문으로 예외 처리한다.
간단히 작성할 수 있는 코드이지만, 2번의 내용과 화살표 함수를 이용해 나의 코드를 리팩토링 해보았다.

let myArr=[1,2,3,4]; 
//빈 배열은 'no value!'를 리턴할 것
//이전 코드
function lookForAverageBefore(arr){
  if(arr.length===0) return 'no value!';
  let sum=arr.reduce(function(sum, cur){
    return sum+cur;
  });
  return sum/arr.length;
}
//리팩토링한 코드
function lookForAverageAfter(arr){
  let len=arr.length;
  if(!len) return 'no value!'; //falsy값 활용
  return arr.reduce((acc, cur)=>acc+cur)/len; //화살표 함수 사용
}

lookForAverageBefore(myArr); //2.5
lookForAverageAfter(myArr); //2.5

4. 배열 중 조건에 맞는 값만 더하기

핵심 : 배열에서 조건에 맞는 값만 더하려면 filter 후 reduce하거나, reduce 할 때 조건을 거는 방법이 있다.
나는 filter로 조건에 맞는 값만 추려서 reduce로 총합을 구했으나,
reduce 안에서 조건을 걸어 해당하는 값만 더하는 방법이 있다.
다만 조건에 맞지 않는 값일 때는 반드시 그냥 누산값을 리턴해줘야 한다.

arr=[1,2,3,4,5,6];
//짝수만 더하기
//방법1
function evenSum01(arr){
  let evenArr=arr.filter(el=> el%2===0);
  return evenArr.reduce((acc,cur)=> acc+cur,0);
}
//방법2
function evenSum02(arr){
  return arr.reduce((acc,cur)=>{
    if(cur%2===0){
    	return acc+cur;
    }else{
      	return acc;//조건에 맞지 않는 값은 더하지 않음
    }
  }, 0);
}

5. 배열에서 가장 큰 값 찾기

핵심 : reduce와 조건문을 사용해 가장 큰 값을 찾는다.
핵심 : 비교시 정하는 첫 값은 누산값으로 정하고, 현재값이 큰 경우 현재값으로 대체한다.
최대값, 최소값 등등......
비교할 때 원리는

  • 최종 리턴할 변수를 선언한다.
  • 먼저 첫 값을 최종 리턴 변수에 할당하고
  • 하나씩 비교해서 비교하여 기준에 맞을 경우 변수를 대체한다.
  • 마지막에 변수를 리턴한다.

이 원리를 이용해 reduce에 적용하자면,

  • 누산값을 첫 값으로 리턴한다.
  • 첫 값이 기준이 되도록 초깃값은 정하지 않는다.
    (reduce는 초기값을 정하지 않으면 첫 값이 누산값이 된다.)
  • 현재값을 하나하나 비교하여 조건에 맞으면 그 현재값을 리턴한다.
  • reduce는 그 전에 리턴한 값이 누산값에 저장된다.
    현재값은 배열의 각 요소로 계속 변하는 값이지만,
    누산값은 계속 그대로 리턴만 하면 그 값이 계속 유지된다.
let arr=[1,9,9,2,5];
let index=0;

function findBiggest(arr){
  //reduce는 콜백함수의 3번째 매개변수로 현재 요소의 인덱스를 전달한다.
  let result= arr.reduce((a, b, curIdx)=>{
    if(a < b){ //조건
      index=curIdx;
      return b;
    }else{
      return a;
    }
  });
  return `가장 큰 값은 ${result}, 이 값의 인덱스는 ${index}`;
}

//조건이 a<b일 경우
findBiggest(arr); //'가장 큰 값은 9, 이 값의 인덱스는 1'
//만약 조건이 a<=b일 경우
//findBiggest(arr); //'가장 큰 값은 9, 이 값의 인덱스는 2'

위 예제에서 reduce안의 조건이 a<b인 경우에는 1번째 인덱스의 값을 제일 큰 값으로 가져오지만,
a<=b인 경우에는 2번째 인덱스의 값을 제일 큰 값으로 가져오니 주의한다.

reduce의 작동방식을 잘 알아야 문제푸는 데 지장이 없다!
아래의 링크에서 #reduce 작동방식을 보면 이해가 쉽다.
javascript MDN - Array.prototype.reduce()

6. reduce의 초기값은 리턴하는 값의 형식에 맞춘다.

핵심 : reduce식을 작성할 때 초기값은 리턴하고자 하는 값의 type에 따라 맞춘다.
필요에 따라
문자열을 리턴해야할 때는 초기값을 '',
숫자를 리턴해야할 때는 0을,
배열을 리턴해야할 때는 []을 초기값으로 설정한다.

7. 배열 중 가장 긴 요소의 length는 나중에 구한다.

핵심 : 배열의 요소 중 가장 길거나 짧은 길이를 구해야 한다면 reduce를 사용한다.
핵심 : 배열의 요소가 문자열 또는 배열인 경우, 길이를 구해야 한다면 값 자체를 구한 뒤 length를 구한다.
reduce를 사용할 때 조회하는 누산값, 현재값은 값 자체를 다룬다.
만약 값의 길이를 구해야 한다면 값 자체를 구한 뒤 나중에 length를 덧붙이는 것이 좋다.

//가장 짧은 문자열의 길이 구하기
let arr=['s2', 'unit1', 'javascript', '고차함수'];

function shortestWord(arr){
  return arr.reduce((acc, cur)=>{
    if(acc.length > cur.length){
      return cur;
    }else{
      return acc;
    }
  }).length; 
  //.length 부분을 제외하면 문자열 자체('s2')가 리턴된다.
  //그러므로 길이를 구하려면 's2'.length 가 필요하다.
}

shortestWord(arr);

8. filter, map, reduce를 조합하여 사용하기

핵심 : 배열이 주어졌을 때, 원하는 값을 한 번에 구하지 말고 나눠서 구한다.
핵심 : 조건에 맞는 배열을 먼저 filter로 구한다.
핵심 : 최대값, 최소값, 총합, 평균 등을 구할 때 reduce를 사용한다.
핵심 : 배열을 변경해야 할 경우 map을 사용한다.
신경써야할 내용이 많지만 한꺼번에 생각하려 하지않고 나눠서 생각하면 값을 구하기가 좀 더 쉬웠다.
만약 조건을 만족하는 값 중 최대값을 구해야 한다면 한꺼번에 구하기보다

  • 조건을 만족하는 값을 먼저 구하고
  • 구한 값 중에서 최대값을 구한다.

이런 방법으로 나눠서 생각한 뒤

  • 조건을 만족하는 값을 구하기: filter 사용
  • 최대값 구하기: reduce 사용

이렇게 해당하는 메서드를 사용해 문제를 풀어나갈 수 있다.

//짝수 중 가장 큰 값 구해서 배열 바꾸기
let arr=[1,3,4,5,8];
function changeBiggestEven(arr){
  //짝수 중 -> 짝수 구하기
  let arrEven=arr.filter((el) => el%2===0);
  //가장 큰 값 구하기
  let biggestEven=arrEven.reduce((acc,cur) =>{
  	if(acc < cur){
      return cur;
    }else{
      return acc;
    }
  });
  //가장 큰 값으로 배열 교체하기
  return arr.map((el)=> biggestEven);
};

changeBiggestEven(arr); //[8,8,8,8,8]

cf. 더 복잡한 경우
만약 각 요소 안에 중첩된 배열 또는 객체가 있을 경우

  • 중첩된 요소: 각 요소 안의 중첩된 배열 또는 객체
  • 중첩된 요소의 최대값, 최소값, 총합, 평균 등을 구하기: reduce
  • 각 요소를 대체해야 할 때: map

정리하자면 map으로 각 요소를,
map메서드를 사용하고, 그 내부에서 중첩된 요소들의 계산을 reduce로 구해 리턴한다. 그러면 map 안에 reduce가 중첩된 형태가 된다.

노트 정리 후 느낀점

콜백함수는 다른 문법에 비해 많이 어색했다. 그러다 계속 작성하니까 좀 더 사용이 익숙해졌는데 참 다행이었다. map, filter 메서드는 사용하는 데 큰 무리가 없었지만 아무래도 reduce의 개념과 이를 활용한 코딩문제는 막상 마주해서 푸니까 자꾸 헷갈리고 쉽지 않았다.
그래서 하나하나 콘솔 창에서 콘솔로 띄워보고 연구했다. 그리고 관련 MDN 문서도 읽다보니 점점 이런? 코딩문제 풀기의 상황에 익숙해져 가고 있다.

이번의 부족한 점

  • reduce를 사용할 때 초기값이 어떻게 중요한지 확실하게 알지 못했다.
  • reduced의 누산값이 각 과정에서 어떤 값으로 교체되고 어떤 원리로 동작하는지 확실히 알지 못했다.
  • 의사코드를 작성하면 확실히 잘 풀리긴 하지만 의사코드를 자꾸 복잡하게 쓰는 경향이 있다.
  • 의사코드를 작성하다보면 문제를 풀 시간이 부족해진다.

부족한 점 보완하기

  • MDN문서와 콘솔창을 통해 reduce가 각 회차별로 실행되는 과정을 학습하고, 직접 작성해보면서 재차 복습했다.
  • reduce를 사용할 때 누산값, 현재값은 먼저 작성해 틀을 만든 뒤, 초기값을 명시한다. 그 이후 각 과정의 리턴값을 생각하며 함수를 작성한다.
  • 의사코드를 작성할 때 간단하게 문장을 작성하고, 중복된 내용은 줄이며 쓰는 연습을 한다.
  • 의사코드가 너무 길어지지 않도록 주의한다.
  • 예시를 정해놓고 각 실행과정을 적어놓고 규칙을 발견하여 작성하도록 한다.
  • 작성한 의사코드는 간결한 내용이 되도록 정리하는 것이 좋다.
  • 코딩문제를 계속 풀어보고 의사코드도 계속 작성한다면, 익숙해질 때 문제푸는 시간이 점점 짧아질 것이다.

😌

profile
프론트엔드 개발자 NH입니다. 시리즈로 보시면 더 쉽게 여러 글들을 볼 수 있습니다!

0개의 댓글