문제

https://school.programmers.co.kr/learn/courses/30/lessons/42842

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 


 

정답 코드

첫 번째 제출
def solution(brown, yellow):
    answer = []
    yellow_wh = (brown-4)/2
    i=1
    while i <=  yellow_wh//2:
        if i * (yellow_wh-i) == yellow:
            answer.append((yellow_wh-i)+2)
            answer.append(i+2)
            break
        i=i+1
    return answer
  • yellow_wh: yellow의 가로 길이+세로 길이
    1. brown = (yellow 가로 길이+세로 길이) * 2 + 4 이므로 중간 합을 기준으로 식을 변형하면 위 코드처럼 됨
  • yellow_wh//2 까지 i 를 1씩 더하면서 반복문 돌리기: yellow = i + (yellow_wh-i) 조건에 맞는 쌍을 찾기 위함
  • yellow 가로>=세로 길이 이므로 애초에 큰 숫자(yellow_wh - i)를 먼저 append 하면 정답 나옴 

 

두 번째 제출 (다른 사람 풀이 참고)
def solution(brown, yellow):
    yellow_wh = (brown-4)/2
    i=1
    while i <=  yellow_wh//2:
        if i * (yellow_wh-i) == yellow:
            return [(yellow_wh-i)+2, i+2]
        i=i+1
  • answer 배열에 append 하지 않고, 바로 배열 형태로 return 하면 코드가 더욱 짧아짐
  •  

문제

https://school.programmers.co.kr/learn/courses/30/lessons/132201

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 


 

정답 코드

-- COALESCE() 함수 사용
SELECT PT_NAME, PT_NO, GEND_CD, AGE, COALESCE(TLNO, 'NONE') AS TLNO
FROM patient
WHERE AGE <=12 AND GEND_CD = 'W' 
ORDER BY AGE DESC, PT_NAME ASC;

-- CASE 문 사용
SELECT PT_NAME, PT_NO, GEND_CD, AGE, 
    CASE 
        WHEN TLNO IS NULL THEN 'NONE'
        ELSE TLNO
    END AS TLNO
FROM patient
WHERE AGE <=12 AND GEND_CD = 'W' 
ORDER BY AGE DESC, PT_NAME ASC;

 


 

배운 점

 

1. COALESCE() 함수

  • '합치다' 라는 의미 
  • 여러 개의 인수를 받아 첫 번째로 NULL이 아닌 인수를 반환
    = 따라서 COALESCE(TLNO, 'NONE') 는 NULL 을 'NONE' 을 반환하고, 그 외는 반환 
  • IS NULL 을 사용 & 조건문 일 때, 간단하게 표현할 수 있는 코드

 

2. CASE 문

  • 문법
CASE 
    WHEN TLNO IS NULL THEN 'NONE'
    ELSE TLNO
END AS TLNO
  • IF ~ ELSE 문을 SQL 식으로 직관적으로 표현한 것 
  • 꼭 IS NULL 이 아니더라도 다양한 상황에서 활용 가능 
  • WHERE 문이 아니라 SELECT 문에서 사용해야 함을 주의

'Algorithm & SQL > Oracle' 카테고리의 다른 글

[SELECT] 타입이 DATE 일 때 처리 방법 | 정렬  (0) 2024.01.09

문제

https://school.programmers.co.kr/learn/courses/30/lessons/144853

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 


 

정답 코드

SELECT BOOK_ID, TO_CHAR(PUBLISHED_DATE, 'YYYY-MM-DD')
FROM book
WHERE CATEGORY = '인문' AND TO_CHAR(PUBLISHED_DATE, 'YYYY') = '2021'
ORDER BY PUBLISHED_DATE ASC;

 


 

배운 점

 

1. 타입이 DATE 일 때 처리 방법

  • 타입이 DATE = CHAR로 타입을 바꾸는 척 해야 처리 가능! 
    • 출력되는 형식 변경: TO_CHAR(PUBLISHED_DATE, 'YYYY-MM-DD')
    • 값 중 일부 글자가 특정 글자에 해당하는 값만 필터링: TO_CHAR(PUBLISHED_DATE, 'YYYY') = '2021'

 

2. 정렬

  • ORDER BY 까먹지 말자. 오름차순은 ASC, 내림차순은 DESC
    • ORDER (X), ARRANGE(X), SORT(X) 

'Algorithm & SQL > Oracle' 카테고리의 다른 글

[Select] COALESCE() 함수 | CASE 문  (1) 2024.01.09

문제 및 레퍼런스

https://school.programmers.co.kr/learn/courses/30/lessons/42862

https://namhandong.tistory.com/152

https://iambeginnerdeveloper.tistory.com/107


 

정답 코드

def solution(n, lost, reserve):
    
    answer = 0  #1번
    new_reserve = set(reserve)-set(lost)  #2번
    new_lost = set(lost)-set(reserve) 
    
    for i in new_reserve:  #2번
        if i-1 in new_lost: 
            new_lost.remove(i-1)  #3번
        elif i+1 in new_lost: 
            new_lost.remove(i+1) 
            
    answer = n - len(new_lost)  #1번
    
    return answer

 


 

배운 점

0. 변수 설정

  • 문풀 전: 내가 정한 규칙에 따라 입력값을 항상 재설정 
    • 문제점: 레퍼런스를 보게 될 경우, 변수 달라 항상 고생. 또한 대문자로 변수 썼으므로 고속으로 코딩하기에 불편
  • 결론: 프로그래머스처럼 입력값 변수가 정해져 있는 경우 그냥 그거 쓰자 

 

1. 리턴 값 초기화의 중요성 

  • 문풀 전: 리턴 값을 초기화 하지 않고, 바로 answer = n - len(new_lost) 식으로 값 할당 
    • 문제점: 코드를 맞게 작성하였는데도, 심지어 정답 코드들과 초기화 부분을 제외하고 코드가 동일한데도  계속 일부 3-5개 케이스를 통과하지 못함 
    • 원인: 이전에 문풀 했을 때 할당되었던 answer이 누적될 수 있음
  • 결론: 항상 리턴 값은 초기화하고 시작하는 것을 습관화하자

 

2. 배열 or 집합 값의 직접 탐색 

  1. 직접 탐색
    • 문풀 전: 항상 for i in range(len(lost)) 식으로 탐색하고 싶은 배열의 길이의 범위를 지정하여 탐색
      • 문제점: lost[i] 식으로 한 번 더 그 값을 지정해주어야 하는 번거로움 발생. 또한 이번 문제처럼 lost 도 탐색해야 하는 경우 무조건 이중 for문 사용하여 배열 값에 접근해야함 
    • 결론: 배열 값에 바로 접근하자. for i in lost
  2. 집합 값 탐색
    • 문풀 전: 집합을 생성하고 집합을 탐색하는 것을 몰랐음
      • 문제점: 이번 문제처럼 공통 원소를 제거하는 set(lost) - set(reserve) 같은 코드를 사용할 수 없음
    • 결론: 배열, 집합 양자 왔다 갔다 하자
      • 배열을 집합으로 만들기: set(lost) ( 결과: {2, 4} )
      • 차집합 (= 공통 원소 제거): set(lost) - set(reserve)
      • 집합도 len(lost), lost.remove(i) 처럼 배열에서 사용하는 메서드 사용 가능

 

3. remove() 메서드

  • 문풀 전: 배열에서 원소 제거할 때 무조건 pop() 메서드 사용
    • 문제점: 메서드 특성 상 스택큐 문제에서 뒤의 원소부터 제거한다는 느낌이 강함 (실제 특정 값만 제거할 수 있는데도). 따라서 부담스러움
  • 결론
    • remove() 메서드를 사용하자.
    • 다만 배열 or 집합 순회하면서 remove() 메서드를 사용할 경우, 순회하는 대상이 달라져 원하는 결과가 나오지 않을 가능성 있음 
      -> lost[:] 식으로 리스트의 전체를 슬라이싱하는 기법 사용하자. 이를 통해 리스트의 모든 요소를 복사하여 새로운 리스트를 생성하고, 이를 순회하면서 각 요소에 접근 가능 

참고 문제

 

2864번: 5와 6의 차이

첫째 줄에 두 정수 A와 B가 주어진다. (1 <= A,B <= 1,000,000)

www.acmicpc.net

 

A, B = map(str, input().split()) #str로 입력

mini = int(A.replace('6', '5')) + int(B.replace('6', '5')) #replace함수
maxi = int(A.replace('5', '6')) + int(B.replace('5', '6'))
print(mini, maxi)
  • 접근 오류 
    • ''.replace() 식으로 gpt한테 이상한 함수 사용법 받아와서 적용해보다가 틀림  
    • 문제의 핵심 로직 생각해낸 것은 맞았지만, replace() 함수를 사용해본 적 없어서 괜히 함수 써야할 것 같은 강박 관념에 틀림
    • input을 str로 받아놓고, A.replace(6, 5) 식으로 int로 함
    • print 할 때 굳이 print(mini, ' ', maxi) 안 하고 위처럼 해도 알아서 공백 넣어 숫자 2개 출력해줌 
    •  

참고 문제

 

5585번: 거스름돈

타로는 자주 JOI잡화점에서 물건을 산다. JOI잡화점에는 잔돈으로 500엔, 100엔, 50엔, 10엔, 5엔, 1엔이 충분히 있고, 언제나 거스름돈 개수가 가장 적게 잔돈을 준다. 타로가 JOI잡화점에서 물건을 사

www.acmicpc.net

M = 1000 - int(input())  // input 받아 한 번에 M 정의
coins = [500,100,50,10,5,1]  // 반복되는 로직의 대상을 coins 배열에 넣기
ans = 0
for coin in coins:
    ans += n//coin
    M %= coin  // M 업데이트
print(ans)

 

비동기 처리 - 1. 비동기와 콜백 글 보러 가기

비동기 처리 - 2. Promise 글 보러 가기

비동기 처리 - 3. Promise Chainig | Error Handling 글 보러 가기

비동기 처리 - 4. Promise API 글 보러 가기

비동기 처리 - 5. microtask 글 보러 가기

 


 

개요

 


 

1. async, await 개요

의미

프로미스 문을 보다 가독성 있게 만들어주는 도구

 

특징
  • function 앞에 async 사용
  • async 키워드가 반드시 있어야 함수 내에서 await 사용 가능 : async + await 은 짝꿍!
  • await = Promise ~ .then 이라고 볼 수 있음

 

예시 코드
async function f() {
  let promise = new Promise((resolve, reject) => {  //async 함수 내에 프로미스도 넣을 수 있음
    setTimeout(() => resolve("완료!"), 1000)
  });
  let result = await promise; // 프라미스가 이행될 때까지 기다림 (*)
  alert(result); // "완료!"
}
f();

// 프로젝트에 적용 
async detect(imageData) {
  if (!this._detector) {
      this._detector = await this._createDetector();
      console.log("model loading success!, detector: ", this._detector);
  }
  this._result = await this._detector.estimateFaces(imageData);
  console.log('this._result: ', this._result);
//... 중략
}

 

에러 핸들링 : try ~ catch 문과 함께 사용 가능!
async function f() {
  try {
    let response = await fetch('http://유효하지-않은-주소');
    let user = await response.json();
  } catch(err) {
    // fetch와 response.json에서 발행한 에러 모두를 여기서 잡습니다.
    alert(err);
  }
}

f();

 


 

2. 프로미스 함수와 비교

프로미스
function showAvatar(githubUser) {
  return new Promise(function(resolve, reject) {
    let img = document.createElement('img');
    img.src = githubUser.avatar_url;
    img.className = "promise-avatar-example";
    document.body.append(img);
    setTimeout(() => {
      img.remove();
      resolve(githubUser);
    }, 3000);
  });
}

 

async, await
async function showAvatar() {
  let img = document.createElement('img');
  img.src = githubUser.avatar_url;
  img.className = "promise-avatar-example";
  document.body.append(img);
  await new Promise((resolve, reject) => setTimeout(resolve, 3000));
	// await은 Promise 및 Promise.all과 함께 사용 가능
  img.remove();
  return githubUser;
}
  • .catch 대신 try ~ catch 문 사용 가능 → 가독성 향상
  • 주의할 점 : async, await은 프로미스 기반임

 


 

3. 비동기 관련 추가로 공부하면 좋을 주제 

비동기 처리 - 1. 비동기와 콜백 글 보러 가기 

비동기 처리 - 2.  Promise 글 보러 가기 

 


 

개요

 


 

1. Promise Chaining (프로미스 체이닝)

의미

순차적으로 처리해야 하는 비동기 작업이 여러 개 있는 경우 사용하는 기법

 

방법 1 : 프로미스를 리턴
  • resolve (result) 하는 것
  • 예시 코드 
return new Promise((resolve, reject) => {   
  this._detector.estimateHands(imageData).then(result => {
      this._result = result;
      console.log(`this._result: `, this._result);

      this._result.forEach((res) => {
          console.log(`${res.handedness} hand keypoints:`);
          res.keypoints.forEach((keypoint, i) => {
              let x = keypoint.x - 320;
              let y = keypoint.y - 240;
              console.log(`Keypoint ${i}: [${x}, ${y}]`);
          })
      })
      resolve(this._result);
  }).catch(e => {
      reject(e);
  });
})

 

방법 2: .then을 여러 번 사용
new Promise(function(resolve, reject) {
  setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)
  alert(result); // 1
  return result * 2;
}).then(function(result) { // (***)
  alert(result); // 2
  return result * 2;
}).then(function(result) {
  alert(result); // 4
  return result * 2;
});

 

fetch와 프로미스 체이닝 함께 이용 가능
  • fetch
    • JS에서 제공하는 네트워크 요청의 생성, 응답을 다루기 위한 API
    • HTTP 요청을 보내거나 서버에서 데이터를 가져올 때 사용됨
    • Promise 기반의 비동기 방식으로 동작
    • 브라우저 환경 or Node.js 에서 사용 가능
  • 예시 코드 : Promise.race 를 사용하여 fetch 요청에 타임아웃을 설정
return Promise.race([
  fetch(resource, Object.assign({signal}, init)).then(response => {  //fetch 함수를 이용하여 네트워크 리소스에 대한 요청 수행 
      clearTimeout(timeoutID);  //fetch 요청이 완료되면 타임아웃을 취소하기 위해 사용됨
      return response;
  }),
  new Promise((resolve, reject) => {
      timeoutID = setTimeout(() => {
          if (controller) controller.abort();
          reject(new Error(`Fetch timed out after ${timeout} ms`));
      }, timeout);
  })
]);

 


 

2. Error Handling (에러 핸들링)

// 실행 순서: catch -> then
new Promise((resolve, reject) => {
  throw new Error("에러 발생!");
}).catch(function(error) {
  alert("에러가 잘 처리되었습니다. 정상적으로 실행이 이어집니다.");
}).then(() => alert("다음 핸들러가 실행됩니다."));
  • .then 구문 안에서 throw new Error 하고, .catch 구문으로 에러 다시 던져서 처리하면 보다 효과적으로 에러 처리 됨
  • 만약 위처럼 에러 핸들링하지 않는다면, 서버에 에러를 알리지 않은 채 스크립트가 죽고 콘솔창에 메시지가 출력 됨.
    : 이 경우 JS 는 전역 에러를 생성하는데, 다시 복구가 어려움

개요

  • 이번 프로젝트 (handpose, face, pose detection) 을 진행하면서 비동기로 작업을 처리하는 경우가 매우 많았음.
  • 특히 모델 로딩, 좌표 예측 에 해당하는 부분이 시간이 오래 걸리는 작업이었기 때문임
  • 그러나 ①비동기 개념에 대한 이론을 매우 오래 전에 배우기도 했고, ②회사의 기존 코드는 Promise 를 활용하여 작성되었는데 나는  async, await  코드 작성법만 알고 있는 상황이어서 주먹구구식으로 따라감. 그래서  Promise 에 대해서도 공부해보고 싶었음 
  • 따라서 비동기 처리에 관한 내용들을 시리즈로 정리할 것임. 이번 글의 모든 코드와 글은 근본적으로  https://ko.javascript.info/callbacks 을 출처로 함 

 


 

1. 비동기 (Asynchronous)

의미
  • 작업이 완료될 때까지 기다리지 않고, 다른 작업을 수행
    = 백그라운드에서 작업을 수행하고, 그 작업이 완료되면 특정 콜백 함수, 프로미스 등을 통해 결과를 처리
  • JS에서 비동기 스케줄링 대표 예시 : setTimeout() , AJAX 요청, 파일 읽기

 

필요성
  • 일반적
    • 대규모 응용 프로그램에서 보다 효율적인 성능 제공
    • 여러 작업을 동시에 수행 가능. 따라서 다수 클라이언트 요청에도 (ex. 네트워크 통신 및 파일 I/O, 이벤트 처리 등) 웹 어플리케이션이 보다 빠르게 동작하고, UX 향상 가능
  • 나의 프로젝트 (구체적으로)
    • createDetector() 함수 : 파일 시스템에 저장된 모델을 불러오는데(I/O 작업) 시간 오래 걸림
    • estimateHands() 함수 : 모델로 예측하는 인공지능 업무 수행하는 데에 시간 오래 걸림
  • 기본적인 비동기 처리 방법 : 콜백

 


 

2. 콜백

의미
  • 어떤 일이 발생했을 때 시스템에서 호출되는 함수 = 나중에 호출할 함수. 따라서 개념 상 주로 비동기 상황 (ex. 이벤트 발생, 비동기 작업 완료) 에서 사용됨
  • 비동기 함수는 콜백을 인수로 반드시 제공해야 함.
    (콜백 : 함수 내 동작이 모두 처리된 후 실행되어야 하는 함수가 들어간 콜백임)
  • 콜백 함수의 의미 : 콜백의 의미와 매우 유사
const fs = require('fs');
// 콜백 함수 : readFile() 함수의 마지막 인자로 전달된 함수
fs.readFile('example.txt', 'utf8', (err, data) => { 
    if (err) {
        console.error('Error reading file:', err);
        return;
    }
    console.log('File contents:', data);
});
console.log('Reading file...');

 

콜백 지옥 (= 멸망의 피라미드)
  • 발생 이유 : 중첩된 콜백 코드가 많아지는 경우 발생
  • 예시 코드
loadScript('1.js', function(error, script) {

  if (error) {
    handleError(error);
  } else {
    // ...
    loadScript('2.js', function(error, script) {
      if (error) {
        handleError(error);
      } else {
        // ...
        loadScript('3.js', function(error, script) {
          if (error) {
            handleError(error);
          } else {
            // 모든 스크립트가 로딩된 후, 실행 흐름이 이어집니다. (*)
          }
        });

      }
    })
  }
});

 

해결법
  • Promise 문 사용
    • 특히 콜백을 단 한 번만 호출하는 함수인 경우, 프로미스화하여 사용하면 좋음
    • 콜백을 단 한 번만 호출할 때만 프로미스화 해야 하는 이유 : 콜백은 2개 이상의 결과를 가질 수 있지만, 프로미스는 1개의 결과만 가지기 때문
    • 프로미스화 : 콜백을 받는 함수를 프로미스를 반환하는 함수로 바꾸는 것 . 프로미스화는 async, await 과 같이 사용하면 좋음
  • async, await 함수 사용 : Promise를 보다 쉽게 사용하는 도구

 


 

요약

  • 비동기 처리는 시간이 오래 걸리는 작업이어도 백그라운드에서 다른 작업을 수행할 수 있도록 함. 따라서 기능 실행의 효율성 측면에서 필수불가결한 작업임.
  • 비동기 처리의 대표적인 방법인 콜백은 콜백 지옥에 빠질 확률이 매우 높기 때문에, Promise 또는 async, await 함수의 활용이 절실

 

이전 시리즈 글 : 코드 최적화 - 1. this.~ 문의 사용 보러가기 

이전 시리즈 글 : 코드 최적화 - 2. 유효성 검사 보러가기

이전 시리즈 글 : 코드 최적화 - 3. for문과 forEach문

 


 

개요

  • 개요는 시리즈 1과 동일 
  • 이하에서는 간결한 코드 작성하는 몇 가지 팁 정리함

 


 

1. 삼항 연산자 ? :  

  • 조건에 따라 값을 선택하는 자바스크립트의 표현 식
// 기본 구조 
(condition) ? trueExpression : falseExpression;
  • 예시 코드 : 프로젝트에 적용
this._result.forEach( (res) => {
  ctx.fillStyle = res.handedness === "Left" ? "Red" : "Blue";  // 조건식 쓸 때 왼쪽처럼 등호 2번 사용 가능!
  ctx.strokeStyle = "White";
  ctx.lineWidth = 2;
  res.keypoints.forEach(keypoint => {
      this._drawKeypoint(ctx, keypoint);
  });
  Object.keys(FINGER_INDICES).forEach(finger => {
      const points = FINGER_INDICES[finger].map(idx => res.keypoints[idx]);
      this._drawPath(ctx, points, false);
  });
});

// 최솟값 찾기
const a = 5;
const b = 10;
const min = (a < b) ? a : b;
console.log(min); // 출력: 5

 


 

2. && 연산자 활용

  • 값이 존재할 때만 출력
  • 예시 코드
const message = "안녕하세요!";
message && console.log(message);

     


 

3. filter 문 활용

  • 배열에서 특정 조건을 만족하는 값만 필터링
  • filter 문은 배열에서만 사용 가능
  • 예시 코드
const numbers = [1, 2, 3, 4, 5];
// 홀수만 필터링
const oddNumbers = numbers.filter(num => num % 2 !== 0);
console.log(oddNumbers); // 출력: [1, 3, 5]

+ Recent posts