18일차 (12-31-2020)

조상래·2020년 12월 31일
0

코드스테이츠

목록 보기
19/73

언더바에 맞아서 정신 못차리는 와중에 재귀를 시작했다. 페어와 함께 진행하는 코플릿이었는데 생각보다 쉽게쉽게 진행 되었다. 물론 삼십분 넘게 머리를 썼던 것이 있기도 했다. 재귀를 활용하는 건 조금 생소했지만 이때까지의 교육 커리큘럼이 어색함을 극복하게 나를 도와줬다. 금방 이해가 갔다. 코드스테이츠 짱!

재귀 코플릿은 총 15문제였는데 그 중 14문제를 페어분과의 티키타카로 레퍼런스 없이 풀었고 한 문제가 한 시간을 넘게 잡아 먹길래 결국 레퍼런스를 봤다. 보니까 조금 허탈감(?)이 느껴졌다. 항상 레퍼런스한테 뚜드려 맞는다.

그 어려웠던 한 문제는 바로 문자열과 배열이 무작위로 들어있는 배열을 뜯어(?) 거기에 내가 찾는 문자열이 있는지 찾는 것! 여기서 핵심은 바로 배열이 들어 있다는것! 물론 배열안에 또 배열이 또 배열이 있다. 중첩의 개수는 얼만큼 될지 알 수 없다. 약간 인셉션 보는 느낌?

요번엔 이 문제를 풀면서 알아낸 한가지를 설명해 보겠다. 문제를 풀면서 가장 고민 됐던것은 배열안의 문자열은 그냥 for 반복문으로 비교할 수 있지만, 만약 배열이 있다면? 2중 for문을 써야하는가? 만약 2중 for문을 썼다고 치자 근데 그 배열안에 또 배열이 있다면? 또 for문을 써야할 것이다. 배열의 중첩이 만약 엄청 많다면, 그럴땐 for문으론 대처가 안될것이다. 그래서 재귀함수를 쓰는 것인데, 재귀함수로 중첩이 되어있는 배열을 한가지로 축소 시키는 방법을 알아보자.

let arr = [1, 2, [3, 4, [5], 6], [7], [[8]],9];

방금 내가 만든 중첩배열이다. 보기만해도 어지럽다. 뭔가 대가족을 보는 기분?? 배열이 중첩 될수록 어린 숫자(?) 이상한소리 그만하고 한가지 배열로 만들어보자.

우리가 원하는 기댓값은 [1, 2, 3, 4, 5, 6, 7, 8, 9]이다.

순서대로 생각해보자. (여기서부터는 나만의 방법으로 한 사고의 과정을 작성한 것이기에 이해가 안갈수도 있다. 그래서 안보는 것이 머리가 덜 아플수도있다... 결과만 보고싶다면 5번으로.)

  1. 먼저 나중에 기댓값이 될 새로운 빈 배열을 선언하자.
function mergeToAnArray(arr) {
  let newArr = [];
  return newArr;
}
  1. 그 다음 for문을 이용하여 배열과 문자열을 구분해주고 만약 문자열이라면 그대로 newArr에 푸쉬.
function mergeToAnArray(arr) {
  let newArr = [];
  
  for (let el of arr) {
    if(Array.isArray(el) {
       console.log(el)
    } else {
    newArr.push(el);
    }
  }
  return newArr;
}
  1. 찾은 배열을 그대로 함수에다가 넣어 주면 그 배열의 요소로만 이루어진 새로운 배열이 전개 될것이다.
// let arr = [1, 2, [3, 4, [5], 6], [7], [[8]],9]; 일때
// mergeToAnArray(arr); 함수를 호출했을 때.

function mergeToAnArray(arr) {
  let newArr = [];
  
  for (let el of arr) {
    if(Array.isArray(el) {
       mergeToAnArray(el) // 첫 번째 여기 걸리는 el은 [3, 4, [5], 6]일 것.
    } else {             // 함수의 el은 또 [5]를 배열로 잡아내 다시 한번 함수로 들어갈 것이다.
    newArr.push(el);
    }
  }
  return newArr;
}
  1. 이렇게 첫 번째 el이 들어가서 호출된 함수의 모습은 바로 이런모습 이라고 상상해 볼 수 있다.
newArr = [3, 4, (newArr = [5])]; 
// 마지막 인덱스인 6이 되기전에 newArr = [5] 리턴 해버려서 6은 없다고 생각하면 된다
// 스코프에 따라 서로 상관하지 않는 변수 newArr 두개 붕 떠있다.
// 만약 마지막으로 실행된 함수의 리턴값이 두 번째로 실행된 함수로 들어가 
// 하나의 요소가 된다면 어떨까? 그렇다면 for문은 제대로 이어서 실행 될 것! 물론 첫 번째 까지도
  1. 어떻게 제대로 된 결과를 볼 수 있을까?
function mergeToAnArray (arr) {
  let newArr = [];
  
  for (let el of arr) {
    if (Array.isArray(el)) {
      newArr = newArr.concat(mergeToAnArray(el));
    } else {
      newArr.push(el);
    }
  }
  return newArr;
}

바로 이렇게 함수안에서 리턴된 변수들을 concat으로 하나하나 묶어서 상위의 변수에게 전달해주는 것이다.

결과는?

잘 정리 되었다!

항상 그렇듯 정확히 이해는 되지 않는다. 머릿속에 두둥실 떠다닐 뿐 ... 그래서 여러가지 시행착오로 떠다니는 것을 차근차근 하나씩 잡아주니 결과엔 도달하는 것 같다. 이런 논리적 사고에 익숙해지기 위해선 노력뿐인것같다. 여러가지 경험으로 실수를 줄여나가는 것! 그러면 결과에 더 빨리 도달할 수 있을 것이다. 노력하자!

profile
Codestates Full IM26기 수료

0개의 댓글