[TIL]21.04.19

박주홍·2021년 4월 19일
0

Today I Learned

목록 보기
2/104

배열 코플릿 오답

8번

function getLargestElement(arr) {
  let temp = arr[0];
  for(let i = 1; i < arr.length; i += 1){
    if(temp < arr[i]){
      temp = arr[i];
    }
  }
  return temp;
}

처음 temp에 arr[0]를 할당해 준 이유는 그 배열들끼리 누가 큰 엘리먼트인지 비교하기위함. 만약 temp에 0이나 -1같은 정수를 넣어줬다면, 그 배열의 요소들중에 처음 temp에 할당해준 값보다 큰 값이 없을 경우 자동으로 temp가 리턴되기 때문에 이를 방지하고자 처음 할당을 arr[0]을 한 것이다.

10번

틀린 코드

function getEvenNumbers(arr) {
  let arrTemp = [];
  for(let i = 0; i < arr.length; i += 1){
    if(arr[i] % 2 === 0 ){
      arrTemp[i] = arr[i];
    }
  }
  return arrTemp;
}

왜 틀렸는 가?
: for문안의 if문은 짝수인지 아닌지를 비교해주는 조건문인데, 만약 짝수가 아니면 arrTemp[i]에 아무 요소도 들어가지 않는 다고 생각하고 리턴을 해봤지만 empty값이 들어가게된다. 이유는 모르겠지만 else로 후처리를 해주지 않는다면 이렇게 값을 직접 할당할때마다 empty값이 할당된다는 것은 확실하다. 해서 메소드를 사용해야하는데 push 메소드를 사용해보겠다.

작동되는 코드

function getEvenNumbers(arr) {
  let arrTemp = [];
  for(let i = 0; i < arr.length; i += 1){
    if(arr[i] % 2 === 0 ){
      arrTemp.push(arr[i]);
    }
  }
  return arrTemp;
}

: 아마 직접 값을 할당을 해줄시에 else처리를 안해주면 빈, 즉 empty값이 할당되는 이유는 여러가지가 있겠지만
1. if문의 조건을 만족하지 못하는 경우 (=else 일때) 반환해야 하는 값이 지정되어 있지 않다. 만약 이러하듯 지정되어 있지않다면 undefined 나 empty 값 등등이 나오게 된다.

또다른 예

function isEitherEvenAndLessThan9(num1, num2) {
  if(num1 % 2 === 0 || num2 % 2 === 0){
    if(num1 < 9 && num2 < 9){
      return true;
    }
  }else{
    return false;
  }
}

: 이 코드에서 Argument로 40과 3 을 받는다면 boolean으로 값이 나와야하지만, undefined 으로 나온다.
그 이유는 두 매개변수가 두 if문에 충족되지 않아 else 처리를 해서 다른 값을 나오도록 코드를 구성해야하지만 그런 반환값이 지정되어 있지 않기때문에, 즉 리턴이 따로 지정되어 있지 않기때문에 쓰레기값 또는 undefined 가 나오는 것이다.


하지만 앞의 배열 코플릿 10번과 내가 틀린 조건문 코플릿 11번 코드의 else처리를 안해서 값이 empty나 undefined 가 나오는 것 중 많이
다른 부분 하나가 있다 그것은...

: 앞의 코드는 return 으로 빈문자열이라도 리턴하라고 코드를 짜줬기때문이다...
하여간 if조건문이 충족되지 않는 경우 else문으로 후처리를 하지 않는다면, 저렇게 배열의 요소가 다른 배열의 요소에 직접 할당할 경우 empty값이 들어간다는 것을 알았다. 왜 그런 것인지는 아고라스테이츠에서 물어본 후 다시 글을 업데이트 하도록 하겠다.

14번

function getElementsAfter(arr, n) {
  let arrTemp = arr.slice(n + 1);
  return arrTemp;
}

: arr.slice(여기서부터, 여기까지);
입출력예시

let output = getElementsAfter(['a', 'b', 'c', 'd', 'e'], 2);
console.log(output); // --> ['d', 'e']

shift와 slice

let input = [1, 2, 3, 4];
shift
:

input.shift(); // ==> 1이 출력됨
input // ====> 2,3,4 가 출력됨

slice
:

input.slice(1); // ===> 2,3,4 가 출력
input; //===> 1,2,3,4 가 출력

** 항상 메소드 MDN참고

주의 해야할 것들 about unshift, shift, pop, push등..
return arr.unshift(1);
return arr.shift();
return arr.pop();
return arr.push(1);

: 등 이것들은 바로 리턴해버리면 arr라는 배열의 길이가 반환하게 되므로 항상 배열의 요소들을 리턴하고 싶을때는

return arr;

이런 식으로 배열을 리턴해주는 편이 좋다.

20번

얇게복사 : 원본배열을 건드리지 않고, 값을 복사해서 할당해주는 복사, 새로운 메모리주소를 정적 or 동적할당해서 새로운 배열을 만드는 복사
깊게복사 : 원본배월을 건드림, 즉 원본배열의 메모리주소에서 값을 변경한다는 소리. 쉽게말해 원본배열의 값이 변경됌.

function removeFromBackOfNew(arr) {
  // arr.pop();
  // return arr;  원본배열을 건드리는 코드임

  let arrTemp = arr.slice(0,arr.length - 1);
  return arrTemp;

}

: 함수 안에 주석처리한 코드처럼 pop은 원본배열을 던드리는 코드임. let arrTemp = arr.pop(); 배열코플릿 20번의 문제조건은 원본배열을 건드리지 말아야, 즉 값이나 메모리 주소가 변경되지 않아야하는 데, pop을 쓰면서 그러지 않기란 쉽지않음. 그래서 slic 메소드로 원본배열을 건드리지 않고 새로운배열에 마지막요소를 제거한 후 할당하는 편이 이문제에 핵심임.

그래서 항상 사용하는 메소드가 원본변수나 배열, 객체등등 데이터가 할당 된, 데이터타입의 주소값이나 변수값을 건드리는지, 건드리면 어떻게 건드리는지 주의깊게 보고 사용하는 습관을 길러야한다..

'입력받은 배열을 수정하지 않아야 합니다(immutability)'

21번

function addToBackOfNew(arr, el) {
  return arr.concat([el]);	// concat은 배열과 배열끼리 합할 수 있도록 도와주는 메소드이므로 el을 []로 묶어줬다.
}				// 그리고 원본배열의 값이 변했는데 테스트가 통과된 걸로 봐선, 원본배월의 데이터주소값을 얘기하는
				// 것 같다는 생각이 들었다.. (데이터주소가 배열의 요소가 더 늘어남에 따라 몇바이트 늘지 않을까?)

function addToBackOfNew(arr, el) {
  let arrTemp = arr.slice();	// arr.slice(); 로 얇은복사를 해서 값을 arrTemp에 할당해준다. (원본배열을 건드리지 않고)
  arrTemp.push(el);		// push() 메소드는 깊은 복사로 배열자체를 건드리는 메소드지만 원본배열과 별개의 데이터주소값을 
  return arrTemp;		// 가지고있는 다른 배열이므로 상관 없다. 그래서 반환값을 arrTemp 배열을 해준다.
}

22번

function addToFrontOfNew(arr, el) {
  let arrTemp = arr.slice();
  arrTemp.unshift(el);
  return arrTemp;
}

: 20, 21번과 마찬가지로 원본배열을 건드리지 않기위해 arr.slice();로 얇은 복사를 해서 그 복사한 배열에서 unshift(el)를 함으로써 원본배열의 값과 메모리 주소값이 변하지않도록 했다.

23번

function getAllElementsButNth(arr, n) {
  // 배열의 길이보다 큰 인덱스를 입력받은 경우, 배열 그대로를 리턴해야 합니다.
  // 배열과 인덱스를 입력받아 인덱스에 해당하는 요소를 제외한 배열을 리턴해야합니다.
  let arrTemp = [];
  // 반복문으로 인덱스 i가 n 과 맞는지 순차적으로 반복하며 확인한다.
  for(let i = 0; i < arr.length; i += 1){
     // 만약 인덱스 i가 n가 맞다면 arr[i]를 arr배열에서 제외한다.
    if(i !== n){
      arrTemp.push(arr[i]);
    }
  }
  // arr[n]값을 제외한 arr를 리턴한다.
  return arrTemp;
}

24번

function createPhoneNumber(arr) {
  // 배열끼리 join('')으로 합친 후, splice()로 각 배열을 선언해 전화번호 앞자리 뒷자리를 할당해 준 후에
  // 백틱으로 변수를 출력템플릿에 맞게 출력한 백틱값을 반환할 것. 
  let temp1 = [];
  let temp2 = [];
  let temp3 = [];

  // 배열의 길이가 8인 경우, 앞에 [0,1,0]이 있다고 가정합니다.
  if(arr.length === 8){
    arr.join('');
    temp1 = arr.slice(0,4);
    temp2 = arr.slice(4);
    return `(010)${temp1.join('')}-${temp2.join('')}`;
  }// 배열의 길이가 11인 경우
  else if(arr.length === 11){
    arr.join('');
    temp1 = arr.slice(0,3);
    temp2 = arr.slice(3,7);
    temp3 = arr.slice(7, arr.length);
    return `(${temp1.join('')})${temp2.join('')}-${temp3.join('')}`;
  }
}

: slice() 메소드를 쓸때 어디부터 어디까지 끊을지 잘 계산해서 사용해야할듯하다.(너무 헷갈렸다는,, 콘솔에도 몇번 쳐서 이걸 이렇게 하면 이렇게 나오나..도 몇십번은 해본듯,..)
쉽게 이해하려면::::
::
arr.slice(여기서부터(해당 인덱스), 여기까지(이 인자가 없으면 배열끝까지 감));

25번

function fibonacci(num) {
  // 피보나치수열에서 0,1은 가장 기본값이므로 배열에 0,1을 먼저 할당하면 수월해질 것같음
  let arr = [0, 1];

  // 반복문에서 피보나치수열을 구하기 수월하게 하기위해 위에서 배열에 0과 1을 미리 할당해놓았는데 만약 num, 즉 매개변수가
  // 0만 들어와버리면 0만 return하는 조건을 만들어야함.
  if(num === 0){
    return [0];
  }

  let arrTemp = [];
  // 피보나치수열의 공식 ===> '구하려는 정수 = 구하려는 정수의 전 숫자 + 구하려는 정수의 전전숫자'
  // 공식에 따라 매개변수의 값, 인덱스만큼 반복문을 돌려서 배열에 할당해, 배열을 최종적으로 리턴하면 될 것임.  
  for(let i = 2; i <= num; i += 1){ // 조건문에서 i <= num 이라하는 이유는 num값의 인덱스만큼 피보나치 수를
    arr.push(arr[i - 1] + arr[i - 2]);  // 구해야하기 때문
  }
  return arr;
}
profile
고통없는 성장은 없다고 할 수 있겠다....

0개의 댓글