repl.it javascript 조금 골치아팠던 문제들

16번 for문

주어지는 배열은 숫자로만 이루어진 배열입니다.
findSmallestElement함수를 이용하여 배열을 작은 수대로 재정렬하고,
배열이 비어있다면 0을 리턴해 주세요.

처음에는 for문에 익숙하지 않아 그냥 문제만 풀고 넘길 요령으로 for문이 아닌 배열을 정렬하는 함수인
array.sort()함수를 이용하고자 했다.

function findSmallestElement(arr) {

    if(arr.length===0) {
      return 0
    } else {
      arr.sort()
      return arr[0]
    }
  }

물론 테스트가 아예 안먹힌 것은 아니었다. 하지만 테스트 케이스 3개 중에서 하나만 계속 통과가 안되는 것을 보고
정석대로 for문을 제대로 구글링 해보자는 생각이 들었다.

그렇게 한 시간쯤 씨름하다가 큰 힌트를 얻고 눈이 뜨였다.
그렇게 해서 나온 정답은

function findSmallestElement(arr) {

  if(arr.length===0) {
    return 0
  } else {
    let min = arr[0]
    for(var i = 0; i<arr.length; i++) {
      if(min>arr[i]) {
        min=arr[i]
      }
    }
    return min
  }
}

먼저 배열의 첫 요소를 변수로 지정하고,
for문을 돌려 하나씩 차례로 비교하면서 만일 첫 요소가 작다면 그대로 첫 요소가 되는 것이다.

예시를 들어보자

인자로 들어오는 arr라는 배열은 다음과 같다. [20, 200, 23, 1, 3, 9]

그렇다면 처음 변수 선언을 통해 arr[0]은 20이 된다.
처음 20은 arr[0]과 비교를 하게 되고, 20은 20과 같아 조건문에 해당하지 않는다.
그 다음 200은 20보다 작아 변수 min에 해당하지 않고, arr[3]인 1과 비교하고 나서야 20보다 작은 1은
조건문 비교를 통해 min에 들어간다.

함수의 목적은 배열에서 가장 작은 수만을 리턴하면 되는 것이기에 배열의 첫번째 요소만 존재하면 된다.
따라서 arr[0]으로 배열에서 가장 작은 수만 리턴할 수 있게 된다.

19번 string

sliceCityFromAddress 함수는 address 를 인자로 받습니다.
address 는 주소를 나타내는 string 입니다.
주어진 주소가 어느 도시 인지를 찾아 해당 주소에서 도시 부분만 삭제한 새로운 주소를 리턴해 주세요.
도시는 무조건 "시" 로 끝납니다. 예를 들어, "서울시".
"도" 와 "시" 는 주소에 한번 밖에 포함되어 있지 않습니다.

예를 들어서 경기도 성남시 중앙공원로 53라는 주소가 있다면 주소에서 성남시만 제외하고
경기도 중앙공원로 53만 리턴해야 하는 것이다.

"경기도 성남시 중앙공원로 53" 				=> 		"경기도 중앙공원로 53"
"서울특별시 강남구 테헤란로 427 위워크타워" 		=> 		"강남구 테헤란로 427 위워크타워"
"경기도 성남시 분당구 판교역로 235" 			=> 		"경기도 분당구 판교역로 235"

그래서 처음에는 이렇게 접근했었다.

  1. split함수를 통해 띄어쓰기를 기준으로 나누어 문자열을 배열로 만들고 (["경기도","성남시","중앙공원로","53"])
  2. for문이나 filter함수 등을 통해 문자열에 "시"가 들어가 있는 요소를 제거한 후 (["경기도","중앙공원로","53"])
  3. 다시 join 함수 등을 사용하여 합치면 되지 않을까 했었다. ("경기도 중앙공원로 53")

근데 문제가 생겼다.
당시에 1번은 무난하게 통과 했지만, 1번에서 나온 ["경기도"]를 다시 ["경","기","도"]로 잘라야 "시"를 지울 수 있다는 생각 밖에 못했어서, ["경","기","도"]까지 만드는 데는 성공했지만 그 다음 시 부분만을 자르는 마땅한 함수를 찾지 못해서 포기했었다.

그 다음으로 나온 정답이 "시"의 indexOf를 구한 다음 그 indexOf의 전후로 잘라내어 다시 합치는 방법이었다.
"경기도 성남시 중앙공원로 53"
"경기도 " + "중앙공원로 53"

  const cityIndex = address.indexOf("시");
  const doIndex = address.indexOf("도")
  if(cityIndex !== -1 && doIndex !== -1) {
    const newhome = address.slice(0,doIndex+2)+ address.slice(cityIndex+2, address.length)
    return newhome
  } if(doIndex == -1 ) {
    const newhome = address.slice(cityIndex+2, address.length)
    return newhome
  }

먼저 "시"와 "도"의 indeOf를 구한다.

그 다음 "시" 글자와 "도"글자가 모두 있는 경우에,
address문자열을 처음에서부터 "도" 글자 다다음까지 한번 끊고,

"경기도 "
  • "경기도" 에서 "도"의 indexOf를 찾으면 그 위치는 "기"와 "도" 사이에 위치하게 된다.
    따라서 "경기도 성남시"의 경우 "도" indexOf에서 +2를 해야지만 "성" 글자 앞에서 끊을 수 있다.

그 다음 "시" 글자 +2에서 시작해 문자열의 마지막까지 끊은 다음

"중앙공원로 53"

합친다.

"경기도 중앙공원로 53"

또한 "도" 가 없는 주소일 경우 처음 부분은 끊을 필요 없이 "시" indexOf+2부터 마지막까지 잘라 그대로 리턴한다.

이 로직으로 테스트 케이스 3개 모두 통과했고, 제출했다.

하지만 나는 slice로 문자열 마지막까지 끊을 때 address.length를 썼다는 점에서 내가 맨 처음 생각했던 접근 방식이 가능했었다는 것을 눈치 챘어야 했다.

며칠이 지나고서야 다른 분의 풀이 코드를 하나 보게 되었는데,

const split = address.split(" ");
    return split.filter(e => !e.includes("시")).join(' ');

단 두줄로 끝내버리시는....

split(" ")함수로 먼저 문자열을 분리한 다음 (["경기도","성남시","중앙공원로","53"])
filter함수를 통해 배열의 각 요소에 "시"가 있는지를 확인하고 없는 요소만 모아서
다시 join(" ")함수로 합친다.

["경기도"] 이 안에서도 글자 하나하나를 또 분리할 필요 없이 그대로 글자 요소에 접근이 가능했던 것이다.

21번 만 나이를 구하는 함수

이것도 처음에는 단순하게 생각했었다. 현재 연도에서 생일 연도를 빼서 리턴하려고만 했었는데,
당연히 통과 못했고 다시 생각해 보다가 월과 일의 비교에 따라 나이가 달라진다는 것을 알았다.

이 함수는 birthday 라는 인자를 받습니다.
이 birthday 는 Date 객체 입니다. birthday 라는 인자를 넣었을 때, 현재를 기준으로 만으로 계산한 나이를 리턴 해주세요.
birthday 는 string이 아닌 Date 객체라는 걸 명심하세요 :)

function getWesternAge(birthday) {

  const current = new Date()
  const currentYear = current.getFullYear()
  const currentMonth = current.getMonth()+1;
  const currentDate = current.getDate()
  
  const birthdayYear = birthday.getFullYear()
  const birthdayMonth = birthday.getMonth()+1
  const birthdayDate = birthday.getDate()
  // 현재와 생일의 Date객체에서 연도, 월, 일을 각각의 변수에 저장한다.
  

  const resultYear = currentYear - birthdayYear
  // 이건 그냥 반복을 싫어해서 쓴 변수
  
  // 여기서 부터는 현재와 생일의 예시를 직접 입력해 보면서 가정했다.

  if(currentMonth < birthdayMonth) return resultYear -1;
  // 생일 월이 더 크다면 생일은 지나지 않았다.
  
    else if(currentMonth > birthdayMonth) return resultYear;
    // 현재 월이 더 크다면 생일은 지났다.
    
    else if(currentMonth = birthdayMonth) {
    // 현재 월과 생일 월이 같다면 이제 일을 비교해야 한다.
    
      if(currentDate < birthdayDate) return resultYear -1
      생일 일이 더 크다면 생일은 지나지 않았고,
      
      else if(currentDate = birthdayDate) return resultYear
      else if(currentDate > birthdayDate) return resultYear
      현재 일이 생일 일보다 크거나 혹은 같으면 생일이 지난 것이다.
    }
}

30번 객체에 접근해 리턴하는 함수

  1. scores 객체가 가지고 있는 키들은 새로운 객체에 포함되어야 합니다. 단, 그 값들은 다음 원리에 따라 숫자로 바뀌어 할당되어야 합니다.
  2. requiredClasses 배열의 요소로는 존재하지만, scores의 키로는 존재하지 않는 항목이 있다면, 해당 요소는 새로운 객체의 키가 되고, 값으로 0을 가져야 합니다. 위에서 예시로 묘사된 객체와 배열이 인자로 들어왔다면, 다음과 같은 객체과 리턴됩니다. 요소간 순서는 다를수 있지만, 채점에 무관합니다.

이 문제가 제일 오래 걸렸고, 제일 힘들었다.

const getExamResult = (scores, requiredClasses) => {

	const convertToNumber = (grade) => {
        if(grade === "A+") return 4.5
        if(grade === "A")  return 4
        if(grade === "B+") return 3.5
        if(grade === "B") return 3
        if(grade === "C+") return 2.5
        if(grade === "C") return 2
        if(grade === "D+") return 1.5
        if(grade === "D") return 1
        if(grade === "F") return 0
    }
    
    const result = {}
    Object.keys(scores).forEach(className => {
        const grade = scores[className]
        result[className] = convertToNumber(grade)
    })
    requiredClasses.forEach(notClassName => {
        if(!Object.keys(result).includes(notClassName)) {
            result[notClassName] = 0;
        }
    })
    return result
}

먼저 최종 결과로 도출할 리턴 값은 객체이므로 변수 result 객체를 먼저 선언한다.
그리고 문자열로 된 학점을 숫자로 변환해 주는 함수를 하나 만들어 준다.
이 함수(convertToNumber)에서 인자로 받는 grade는 아래에서 선언한다.

scores 객체에서 key값들만 따로 빼 내어(Object.keys(scores)) forEach함수를 돌려서 score의 key값들에 대한 value 값을 새로운 grade 변수에 저장한다(const grade = scores[className]).

그 다음 Value값들을 모아 convertToNumber함수를 돌려 문자열을 숫자로 바꿔준 후(convertToNumber(grade)), 그 값을 result 객체의 각 value값으로 넣는다.

남은 것은 scores객체에 없는 과목들이다.
requiredClasses 배열을 className이라는 인자로 한번씩 요소를 빼내와서(requiredClasses.forEach())

result함수의 키 값에 포함되지 않는다면(if(!Object.keys(result).includes(notClassName)))
그 요소를 result 객체의 key값으로 넣은 후 value값으로는 0을 부여한다(result[notClassName] = 0;).

좋은 웹페이지 즐겨찾기