2022.9.4. 일요일 TIL: js 콜백함수, 프로그래머스 실패율 javascript, Nodejs Express 구현, SQL 리트코드

Dorito·2022년 9월 4일
0

공부 기록

목록 보기
17/71

하루 개요

  • 하루 한 것 ❌ 🔺✅
    코어 자바스크립트 챕터 3 복습 (추가 정리)
    코어 자바스크립트 챕터 4 공부
    알고리즘 문제 1 문제 풀기
    리트코드 SQL 문제 1 문제 풀기
    네트워크 스터디 (오전 10시)
    Node.js 구현
  • 만약 시간이 된다면 자료 구조 공부 || 운영체제 공부

콜백함수

다른 함수 또는 메서드에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수

즉 어떤 함수 X를 호출하면서 '특정 조건일 때 함수 Y를 실행해서 나에게 알려달라'는 요청을 함께 보낸다.
이 요청을 받은 함수 X 입장에서는 해당 조건이 갖춰졌는지 여부를 스스로 판단하고 Y를 직접 호출한다.

- 콜백함수 예제

   Array.prototype.map(callback(currentValue[, index[, array]])[, thisArg])

map 메서드는 첫 번째 인자로 callback함수를 받고, 생략 가능한 두 번째 인자로 콜백 함수 내부에서 this로 인식할 대상을 특정할 수 있다.
thisArg를 생략할 경우, 일반적인 함수와 마찬가지로 전역객체가 바인딩된다.

메서드 대상이 되는 배열의 모든 요소들을 처음부터 끝까지 하나씩 꺼내어 콜백함수를 반복 호출하고, 콜백 함수의 실행결과들을 모아 새로운 배열을 만든다.

콜백함수도 함수이기 때문에 기본적으로 this가 전역객체를 참조하지만, 제어권을 넘겨받을 코드에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조하게 된다.

this를 활용한 map 메서드

메서드 구현 핵심은 call/apply 메서드에 있다.
this에 thisArg 값이 있을 경우 그 값을, 없을 경우에 전역객체 지정함
첫 번째 인자에는 메서드의 this가 배열을 가리킬 것이므로 배열의 i번째 요소 값
두번째 인자에는 i 값
세 번째 인자에는 배열 자체를 지정해 호출함.

객체 메서드를 콜백 함수로 전달하면 해당 객체를 this로 바라볼 수 없게 된다.
https://ko.javascript.info/callbacks

콜백 지옥

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 {
            // 모든 스크립트가 로딩된 후, 실행 흐름이 이어집니다. (*)
          }
        });

      }
    })
  }
})

=> ES6 promise Generator 도입, ES2017 async, await 도입

async/await

비동기 작업을 수행하고자 하는 함수 앞에 async를 표기하고
함수 내부에서 실질적인 비동기 작업이 필요한 위치마다 await를 표기하는 것 만으로 뒤의 내용을 promise로 자동 전환하고, 해당 내용이 resolve된 이후에야 다음으로 진행된다. (= promise then과 흡사한 효과)

프로그래머스 실패율 JavaScript 풀이

  • 제한사항
    스테이지의 개수 N은 1 이상 500 이하의 자연수이다.
    stages의 길이는 1 이상 200,000 이하이다.
    stages에는 1 이상 N + 1 이하의 자연수가 담겨있다.
    각 자연수는 사용자가 현재 도전 중인 스테이지의 번호를 나타낸다.
    단, N + 1 은 마지막 스테이지(N 번째 스테이지) 까지 클리어 한 사용자를 나타낸다.
    만약 실패율이 같은 스테이지가 있다면 작은 번호의 스테이지가 먼저 오도록 하면 된다.
    스테이지에 도달한 유저가 없는 경우 해당 스테이지의 실패율은 0 으로 정의한다.

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

  • 내 풀이
const solution = (n, stages) => {
  const totalUser = stages.length;

  let isZeroArray = [];
  let failedPercentsMap = new Map();

  for (let i = 1; i <= n; i++) {
    const completedUserCount = stages.filter((elem) => elem >= i).length;
    const failedUserCount = stages.filter((elem) => elem === i).length;
    const percent = failedUserCount / completedUserCount;
    if (failedUserCount * completedUserCount === 0) {
      isZeroArray.push(i);
    } else {
      failedPercentsMap.set(i, percent);
    }
  }
  const sortedStagesbyPercent = [...failedPercentsMap].sort(
    (a, b) => b[1] - a[1]
  );
  const sortedStagesOnly = sortedStagesbyPercent.map((elem) => elem[0]);
  const sortedIsZeroArray = isZeroArray.sort((a, b) => a - b);

  return [...sortedStagesOnly, ...sortedIsZeroArray];
};

mutable한 로직이라서 (isZeroArray) 좋은 코드는 아니다.
map 자료 구조 사용함!

리팩토링..
1. if 문 조건 바꿈

// 1
failedUserCount === 0 || completedUserCount === 0

// 2
failedUserCount * completedUserCount === 0

if문 조건을 후자로 바꿈

  1. for문 돌릴때 i 범위가 어정쩡하게 둬서 가독성이 좋지 못하다. (바로 의미 파악하기 힘든듯) -> 수정
  for (let i = 0; i < n; i++) {
    const completedUserCount = stages.filter((elem) => elem > i).length;
    const failedUserCount = stages.filter((elem) => elem === i + 1).length;
    const percent = failedUserCount / completedUserCount;
    if (failedUserCount * completedUserCount === 0) {
      isZeroArray.push(i + 1);
    } else {
      failedPercentsMap.set(i + 1, percent);
    }
  }
  for (let i = 1; i <= n; i++) {
    const completedUserCount = stages.filter((elem) => elem >= i).length;
    const failedUserCount = stages.filter((elem) => elem === i).length;
    const percent = failedUserCount / completedUserCount;
    if (failedUserCount * completedUserCount === 0) {
      isZeroArray.push(i);
    } else {
      failedPercentsMap.set(i, percent);
    }
  }

요캐 바꿈 !

나머지 리팩토링은 실력이 딸려서 잘 모르겠다.
reduce로 풀 수 있을 것 같은데

참고 사이트: https://nukw0n-dev.tistory.com/13 [찐이의 개발 연결구과:티스토리]

  • map 정렬하는 법
mapToArray.sort((a, b) => b[1] - a[1]); // value값 기준 내림차순정렬

mapToArray.sort((a, b) => b[0] - a[0]); // key값 기준 내림차순정렬

mapToArray.sort((a, b) => a[1] - b[1]); // value값 기준 오름차순정렬

mapToArray.sort((a, b) => a[0] - b[0]); // key값 기준 오름차순정렬
  • 제출 결과

알고리즘 뻘짓


(사진에선 변수명 오탈자 있는데 수정함)
1번 테케만 틀림... 이런 경우!

  1. 범위에 맞는 데이터 랜덤 생성해서, 직접 검증해보기
  2. 백준이라면 게시판 뒤져보기
  3. 주변 사람에게 코드 보여주면서 물어보기
  4. 분기, 케이스가 나뉘는 부분을 의심해보기
  5. 엣지 포인트 찾아보기

반례 케이스를 직접 찾은건 처음이다~ !!
오류나서 헤매고 있었는데 다른 분 조언으로 completedUserCount가 0인 경우 percent가 무한대가 될 가능성이 있다고 해주심.
그래서 디버깅 해보니 console.log(solution(3, [2, 2, 2])); 의 경우에 마지막 i = 2 일 때 completedUserCount 가 0이 나온다.

그래서 if 문 쪽에 로직 바꾸니까 성공!!
근데 솔직히 너무 코드가 드러움 ㅎ

아 근데 프로그래머스 1등 코드보다 내가 처리시간이 더 빠름^^ 하 미치겟네 ~ ㅋ (자뻑 중)

  • 다른 사람 풀이

풀이 1

function solution(N, stages) {
    let result = [];
    for(let i=1; i<=N; i++){
        let reach = stages.filter((x) => x >= i).length;
        let curr = stages.filter((x) => x === i).length;
        result.push([i, curr/reach]);
    }
    result.sort((a,b) => b[1] - a[1]);
    return result.map((x) => x[0]);
}

풀이 2

개쩐다
현타와 이런 개쩌는 코드를..!!!

살짝 고쳐서 쳐봄

const solution = (n, stages) => {
  return [...Array(n).keys()]
    .map((x) => x + 1)
    .map((level) => {
      const passed = stages.filter((stage) => stage >= level).length;
      const failed = stages.filter((stage) => stage === level).length;
      return [level, failed / (passed + failed)];
    })
    .sort((a, b) => b[1] - a[1])
    .map((elem) => elem[0]);
};

어떻게 이런 코드를. ㅠ ㅠ

음 근데 실력이 늘었나 싶다가도 걱정이 되는게 내가 2단계를 풀 수는 있을까...라는 생각이 든다.
(정신승리: 근데 처음 시작할 때 내가 와.. 아무것도 모르는데 1단계를 풀어낼 수 있을까 스스로;; 이랬는데 요즘은 풀려서 기분 좋다!)
사실 1단계는 문제 제시해준 대로 걍 처리하면 문제가 풀리는 경우가 많은 것 같은데도, 이것도 여전히 어려워하는 내 모습 때문에 걱정된다.
그리고 사실 코드 유형 돌려막기인 느낌도 들어서 이게 진짜 내 실력인건가 (늘었다고 판단할 수 있을까) 의문도 든다. 성장속도도 더딘 것 같다. 그래도 꾸준히 포기만 하지말자!

Node.js Express 프레임워크 구현

CRUD 구현함

근데 Delete 부분 자꾸 오류남.. 열받음!!
내일 해야지..

const { response } = require("express");
const express = require("express");
const app = express();
const fs = require("fs");
const template = require("./lib/template");
const path = require("path");
const sanitizeHtml = require("sanitize-html");
const qs = require("querystring");

app.get("/", (req, res) =>
  fs.readdir("./data", function (error, filelist) {
    title = "Welcome";
    description = "Hello, Node.js";
    list = template.list(filelist);
    html = template.HTML(
      title,
      list,
      `<h2>${title}</h2>${description}`,
      `<a href="/create">create</a>`
    );
    res.send(html);
  })
);

app.get("/page/:pageId", (request, response) => {
  fs.readdir("./data", function (error, filelist) {
    var filteredId = path.parse(request.params.pageId).base;
    fs.readFile(`data/${filteredId}`, "utf8", function (err, description) {
      var title = request.params.pageId;
      var sanitizedTitle = sanitizeHtml(title);
      var sanitizedDescription = sanitizeHtml(description, {
        allowedTags: ["h1"],
      });
      var list = template.list(filelist);
      var html = template.HTML(
        sanitizedTitle,
        list,
        `<h2>${sanitizedTitle}</h2>${sanitizedDescription}`,
        ` <a href="/create">create</a>
          <a href="/update/${sanitizedTitle}">update</a>
          <form action="/delete_process" method="post">
            <input type="hidden" name="id" value="${sanitizedTitle}">
            <input type="submit" value="delete">
          </form>`
      );
      response.send(html);
    });
  });
});

app.get("/create", (request, response) => {
  fs.readdir("./data", function (error, filelist) {
    var title = "WEB - create";
    var list = template.list(filelist);
    var html = template.HTML(
      title,
      list,
      `
      <form action="/create_process" method="post">
        <p><input type="text" name="title" placeholder="title"></p>
        <p>
          <textarea name="description" placeholder="description"></textarea>
        </p>
        <p>
          <input type="submit">
        </p>
      </form>
      `,
      ""
    );
    response.send(html);
  });
});

app.post("/create_process", (request, response) => {
  var body = "";
  request.on("data", function (data) {
    body = body + data;
  });
  request.on("end", function () {
    var post = qs.parse(body);
    var title = post.title;
    var description = post.description;
    fs.writeFile(`data/${title}`, description, "utf8", function (err) {
      response.writeHead(302, { Location: `/?id=${title}` });
      response.end();
    });
  });
});

app.get("/update/:pageId", (request, response) => {
  fs.readdir("./data", function (error, filelist) {
    var filteredId = path.parse(request.params.pageId).base;
    fs.readFile(`data/${filteredId}`, "utf8", function (err, description) {
      var title = request.params.pageId;
      var list = template.list(filelist);
      var html = template.HTML(
        title,
        list,
        `
        <form action="/update_process" method="post">
          <input type="hidden" name="id" value="${title}">
          <p><input type="text" name="title" placeholder="title" value="${title}"></p>
          <p>
            <textarea name="description" placeholder="description">${description}</textarea>
          </p>
          <p>
            <input type="submit">
          </p>
        </form>
       `,
        `<a href="/create">create</a> <a href="/update?id=${title}">update</a>`
      );
      response.send(html);
    });
  });
});

app.post("/update_process", (request, response) => {
  var body = "";
  request.on("data", function (data) {
    body = body + data;
  });
  request.on("end", function () {
    var post = qs.parse(body);
    var id = post.id;
    var title = post.title;
    var description = post.description;
    fs.rename(`data/${id}`, `data/${title}`, function (error) {
      fs.writeFile(`data/${title}`, description, "utf8", function (err) {
        response.writeHead(302, { Location: `/page/${title}` });
        response.end();
      });
    });
  });
});

app.post("/delete_process", (request, response) => {
  var body = "";
  request.on("data", function (data) {
    body = body + data;
  });
  request.on("end", function () {
    var post = qs.parse(body);
    var id = post.id;
    var filteredId = path.parse(id).base;
    fs.unlink(`data/${filteredId}`, function (error) {
      response.redirect("/");
    });
  });
});

app.listen(3000, () => console.log("Example app listening on port 3000"));

삭제 프로세스 왜 안댐.. ; ; ; 휴

SQL 이론 복습

리트코드 SQL 문제 풀이하려 했는데 SQL 개념 복습을 다시 해야겠다.
공부하면서 옵시디언에 필기해뒀던거 다시 벨로그에 올림

1) SQL이란?

= Structured Query Language, DB에 접근하고 조작하기 위한 표준언어
하는 일: 데이터 검색, 삽입, 수정, 삭제, DB 생성, 테이블 생성 등 ~엑셀 데이터 분석이랑 비슷

DB: 공유 목적으로 통합하여 관리되는 데이터 모음 (Maria DB, Amazon Redshift, Oracle DB 등 종류 많음)

  • 검색과 분석에 사용되는 기본 사용 방법은 DB 종류 관계 없이 동일함

  • 테이블 구조 확인: DESC 테이블명; (describe 기술하다 줄임말)

렌탈 테이블에 아이디 모음 -> 북 테이블에는 책 아이디만 모아서 속성 뽑아냄, 유저 테이블에는 책 아이디만 뽑아서 속성 뽑아냄

행 row 열 column
테이블 = 컬럼 + 레코드 -> 집합체: 데이터 베이스
컬럼: 주제, 제목
레코드: 내용

주로 사용하는 SQL 명령어

select 검색대상 : 검색하기~ 엑셀에서 필터랑 비슷
from 테이블 이름 : 데이터 불러오기 
where 조건: 조건을 걸기
  • SELECT문의 기본 문법
book 테이블에서 모든 책의 title과 author 컬럼을 검색한다

SELECT title, author  (엔터키)
명령		검색할 컬럼
FROM book;
테이블

SELECT는 컬럼을 중심으로 검색하는 명령어

  • 모든 데이터를 가져오는 법 -> * = all
SELECT *
FROM tablename;
  • 중복테이터 빼고 보기 -> DISTINCT
DISTINCT 컬럼1(ex:제목);
-> 결과: 어린왕자
*cf* 엑셀~ 중복된 항목 제거

DISTINCT 컬럼1, 컬럼2(ex: 제목, 저자); 
-> 한 쪽 컬럼에 중복이 있어도 다른 쪽 컬럼 값이 다르면 다르게 취급한다
-> 어린왕자 김철수, 어린왕자 김영희

뚜렷한, 분명한 의미 ~ 뒤에 나오는 컬럼의 중복을 제거하고 보여준다.
distinct 제목, 저자 -> 한 뭉탱이로 봐서 조금이라도 다르면 반동분자여~

  • DISTINCT 기본 문법: ==검색할 데이터 앞에 DISTINCT를 입력하여 사용==
SELECT(명령) DISTINCT title,author(검색할 컬럼)
FROM book(테이블);
  • 조건을 추가하여 검색하기 = WHERE
SELECT *(검색할 컬럼)
FROM book(테이블)
WHERE title='돈키호테'(조건);
  • 책 정보를 저장하는 book 테이블에서 제목이 '돈키호테'인 책 검색하고 싶다
    = book 테이블 내 title 컬럼에서 돈키호테라는 책을 찾아라 → 해서 행 부분 쫙 찾아줌
    '' → 문자라서 써줌

셀렉트는 항상 맨 앞에 고정!


하루 마무리

  • 내일 할 것 ❌ 🔺✅
    코어 자바스크립트 챕터 3 복습 (추가 정리) ✅
    코어 자바스크립트 챕터 4 공부 ✅
    알고리즘 문제 1 문제 풀기 ✅
    리트코드 SQL 문제 1 문제 풀기 ❌ => 대신 SQL 개념 복습..
    네트워크 스터디 (오전 10시) ❌ => 스터디장 잠수..;
    Node.js 구현 ✅

  • 만약 시간이 된다면 자료 구조 공부 || 운영체제 공부

  • 하루 반성
    구현 오류 잡는게 너무 오래걸린다
    뽀모도로 기법이 그렇게까지 도움이 되는 것 같지 않다.

  • 피드백
    뽀모도로 기법은 진짜 최악으로 집중 안될 때 해야겠다.
    시간 분배를 잘 해야겠다. (하루 시간표를 짜자.)

  • 내일 할 것
    운영체제 공부
    코어 자바스크립트 챕터 4 복습
    코어 자바스크립트 챕터 5 공부
    알고리즘 1문제 풀기
    SQL 개념 복습하기
    네트워크 공부하기 (1강)
    Node.js 구현

월수금 알고리즘 & 자료구조 + 운영체제 + 구현
화목토 SQL + 네트워크 + 코어자스 + 구현

0개의 댓글