[JS] 백준 node.js 입출력, 외우지 마세요

Seungbo Shim·2025년 1월 31일
1

Algorithm

목록 보기
11/11

프론트엔드 개발자의 고충

은 바로 자바스크립트라는 언어로도 코테를 준비해야 한다는 것이다.
C++처럼 온갖 자료구조가 마련된 언어도, 파이썬처럼 세상 짧은 문법의 언어도 아닌,
자바스크립트로 코딩 테스트를 준비해야 한다니... 곤란..허다

특히 자바스크립트는 입출력부터가 골치 아프다.
그래도 프로그래머스나 SWEA처럼 solution 함수만 구현하면 되는 플랫폼은 나름 할 만하다.

하지만,

현대자동차 계열 코테는 소프티어에서 보기 때문에,
자바스크립트 코테를 위해서라면 입출력을 숙지하긴 해야 한다.
여간 슬픈 일이 아닐 수 없다.

그렇다고 자바스크립트 입출력을 찾아보면…
막상 이걸 죄다 외워야 한다고? 싶다.
그 순간 바로 백준 끄고 프로그래머스 키게 만든다.. 흑흑 😿

그러던 중 나를 구원해 준 게시글을 발견.
Softeer(소프티어) JavaScript 코딩 테스트 입력 방법 [INPUT]
외우지 않고, 공식문서의 readline 입출력 예제를 건드리는 방법!

Readline?

자바스크립트 입출력에는 크게 두 가지가 있다.

fs (File System): 파일 시스템을 이용한 입출력.
readline: 한 줄씩 입력을 받는 방식.

보통 코딩 테스트 플랫폼은 입력을 파일로 받기 때문에 fs 를 추천하지만,
외울 자신이 없다면 readline 을 사용하자.
readline 은 외우지 않아도, 코딩 테스트 플랫폼마다 상단에 있는 레퍼런스 공식문서를 긁어올 수 있어서 참 좋다 흐흐

1️⃣ Node.js 공식문서 접속!
2️⃣ Readline 문서를 들어가자
3️⃣ Example: Tiny CLI 섹션에 바로 그 예제가 있다!

입출력 예제를 긁어와보자.

const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  prompt: 'OHAI> '
});

rl.prompt();

rl.on('line', (line) => {
  switch (line.trim()) {
    case 'hello':
      console.log('world!');
      break;
    default:
      console.log(`Say what? I might have heard '${line.trim()}'`);
      break;
  }
  rl.prompt();
}).on('close', () => {
  console.log('Have a great day!');
  process.exit(0);
});

본 코드를 실행하면, 대략 ‘hello’ 를 치기 전까지는 shell처럼 프롬프트가 입력을 계속 받아준다.

readline.createInterface()

readline.createInterface() 메서드는 readline을 사용하기 위한 인스턴스를 만든다.
createElement() 라던지, axios.create() 같은 느낌이다.

rl.on(’EVENT’, () => {})

특정 이벤트가 발생하면, 콜백함수를 실행한다.
이벤트에는 여러 행동이 올 수 있지만, line과 close 두 개만 공식문서를 살펴보자.

line
‘line’ 이벤트는 input 스트림이 \n\r, or \r\n 을 수신할 때 발생합니다.
Enter, Return 키를 누를 때마다 발생

close
'close' 이벤트는 다음 행동이 일어나면 발생합니다.

  • rl.close() 메서드 호출
    readline.Interface 가 input, output 스트림 중단
  • input 스트림이 'end' 이벤트를 수신
  • input 스트림이 EOT(End-of-Transmission) 신호를 수신합니다.
    ctrl + D 키 수신
  • input 스트림이 ctrl + C 키를 수신받아 SIGINT 신호를 받고, SIGINT를 수신하는 이벤트리스너가 없을 경우

따라서 위의 예제를 풀어본다면,

input 스트림을 열어놓고 line 이벤트를 수신하여 rl.on(’line’, ()=>{}); 의 콜백함수를 실행하다가,

close 이벤트를 수신하면 rl.on(’close’, ()=>{}); 의 콜백함수를 실행한다.

rl.close()

위의 close 이벤트를 유발하는, readline의 입력 중단 메서드

rl.question(’query’, () => {})

브라우저 환경에서의 Window.prompt() 처럼 질문 프롬프트를 받는다. 쓸일은 그다지…?

rl.question('What is your favorite food? ', (answer) => {
  console.log(`Oh, so your favorite food is ${answer}`);
});

그래서 어떻게 하는데

이제 본격적으로 코딩 테스트에서 사용할 수 있는 형태로 코드를 정리해보자.

const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

rl.on('line', (line) => {
	/*
	* 
	* 🅰️ 입력을 받을 곳
	* 
	*/
}).on('close', () => {
	/*
	* 
	* 🅱️ solution을 수행할 곳
	* 
	*/
  process.exit(0);
});

이렇게 🅰️, 🅱️ 섹션으로 나눌 수 있다.

한 줄만 입력받기

연습을 위해 딱 한 줄만 입력받아보자.

1️⃣ 입력값을 저장할 input 선언
2️⃣ 🅰️ 섹션에서 입력을 받아 input에 저장
3️⃣ 🅱️ 섹션에서 입력값 처리 → 여기서는 🅰️ 에서 해도 무방하다.
4️⃣ 🅱️ 섹션에서 솔루션 작성 solution 함수를 따로 작성해도 좋다.
5️⃣ process.exit() 으로 코드 종료 처리

const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

// 1️⃣ 입력값을 저장할 input 선언
let input;

rl.on('line', (line) => {

  // 2️⃣ 🅰️ 섹션에서 입력 받기
  input = line;
  
}).on('close', () => {

  // 3️⃣ 🅱️ 섹션에서 입력값 처리
  const N = parseInt(input);

  // 4️⃣ 🅱️ 섹션에서 솔루션 작성
  console.log(N);

  // 5️⃣ process.exit() 으로 코드 종료 처리
  process.exit(0);
});

여러 줄을 한번에 입력 받기 ⭐️

백준 7568: 덩치 를 예시로 가져왔다.
입력은 다음과 같다.

5
55 185
58 183
88 186
60 175
46 155

N 혹은 T를 먼저 입력받고, 데이터를 그만큼 입력받는 흔한 방@식이다. 그래서 어떻게 할건데?

1️⃣ 입력값을 저장할 빈 배열 lines 선언
2️⃣ 🅰️ 섹션에서 입력을 받아 lines에 push
3️⃣ 🅱️ 섹션에서 입력값 처리
4️⃣ 🅱️ 섹션에서 솔루션 작성 solution 함수를 따로 작성해도 좋다.
5️⃣ process.exit() 으로 코드 종료 처리

위의 과정으로 입력을 처리하자!

const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

// 1️⃣ 입력값을 저장할 빈 배열 lines 선언
const lines = [];

rl.on('line', (line) => {

  // 2️⃣ 🅰️ 섹션에서 입력을 받아 lines에 push
  lines.push(line.trim());
  
}).on('close', () => {

  // 3️⃣ 🅱️ 섹션에서 입력값 처리
  const N = parseInt(lines[0]);
  const people = [];

  for (let i=1; i<N+1; i++) {
    const input = lines[i].split(" ");
    const [weight, height] = [parseInt(input[0]), parseInt(input[1])];
    people.push({weight, height});
  }

  // 4️⃣ 🅱️ 섹션에서 솔루션 작성
  const rank = Array(N).fill(1);
  
  for (let i=0; i<N; i++) {
    for (let j=0; j<N; j++) {
      if (people[i].weight < people[j].weight && people[i].height < people[j].height) {
        rank[i]++;
      }
    }
  }

  console.log(rank.join(" "));

  // 5️⃣ process.exit() 으로 코드 종료 처리
  process.exit(0);
});

3️⃣ 번 까지의 과정을 거치면 입력값이 처리되어 다음과 같이 저장된다.

N = 5 
people = [
  { weight: 55, height: 185 },
  { weight: 58, height: 183 },
  { weight: 88, height: 186 },
  { weight: 60, height: 175 },
  { weight: 46, height: 155 }
]

다만, 이 방법은 입력 후 Ctrl+C 로 입력을 강제 종료해줘야 솔루션이 실행된다.

지정한 횟수만큼 입력받기

그래서 우리가 C++에서 하던 대로,
강제종료 없이 N 만큼 반복문을 돌면서 5개의 입력을 받는 형식을 연구했지만,

1️⃣ count 변수를 만들고
2️⃣ count === 0 일 때 N에 저장
3️⃣ 이후에는 people 배열에 데이터를 저장
4️⃣ count > N이 되면 rl.close() 호출하여 입력 중지 

그….. 이럴거면 그냥 한번에 입력받는 게 7천만배 정도 낫지 않을까? 싶어서 그만뒀다.
자바스크립트 코테, 이제 무섭다고 피하지 말쟈.

혹시 몰라서 fs도 준비했어

fs 모듈이 쓰기는 정말

시간초과의 지옥

(25.02.02 추가)
그러나 시간초과의 지옥을 겪었다.
왜지.. readline 때문인가? 싶어서 fs 모듈로도 돌려봤으나 똑같다.

단순하지만, 까먹을 수 있음..ㅜ

profile
그래요 나 지금 거렁뱅이에요

0개의 댓글

관련 채용 정보