알고리즘에서 데이터 입/출력 받는 방법 with Python

COCOBALL·2023년 5월 8일
2

알고리즘

목록 보기
21/37

코딩 테스트를 준비할 때 사용하는 플랫폼의 종류에 따라서 제출하는 형식, 입력받는 형식 등이 달라지게 된다.

대표적으로 코딩 테스트를 시행하는 프로그래머스, 구름 플랫폼은 solution 이라는 함수를 호출식으로 인자를 넘겨받게 되어 별도의 input 처리가 필요하지 않다.

그러나 백준, SWEA와 같이 사용자가 input 처리부터 해야하는 플랫폼이 있다.

데이터를 입력받는 형식에는 다양한 방식이 있다.

입력방식

🔵 파일로 입력받기

  • sys 모듈 import
  • 표준 입력을 파일 읽기로 설정
import sys

#표준입력을 파일로 설정
sys.stdin = open("input.txt", "r")

🔵 데이터를 입력받아 정수로 변환

  • input() : 데이터를 한 줄로 입력
  • int() : 정수로 변환
N = int(input())
print(N)

# 입력
>>> 3
# 결과
3

🔵 데이터를 입력받고 공백으로 구분된 문자를 입력받기

  • input().split(구분 문자): 데이터를 한 줄로 읽고 구분 문자로 나눠서 문자로 이루어진 리스트로 입력
print(input().split())

# 입력
>>> a b c 
# 결과
['a', 'b', 'c']

🔵 데이터를 입력받고 공백으로 구분된 문자를 정수로 반환

  • map(형식, 리스트) : 여러개의 데이터를 형식에 맞춰서 다른 형태로 변환함
N, M = map(int, input().split())
print(N, M)

# 입력
>>> 1 2
# 결과
1 2

이때 리스트에 있는 요소의 갯수에 맞춰서 변수의 개수를 해줘야 함

→ 변수의 개수에 맞춰서 입력을 해줘야 함

변수와 입력의 개수를 다르게 설정하면 아래와 같은 오류 발생

N, M = map(int, input().split())
# 1 2 3 입력
Traceback (most recent call last):
	File "<input>", line 1, in <module>
ValueError : too many values to unpack (expected 2)

🔵 1차원 배열(리스트) 입력받기

→ 입력 데이터가 여러개이거나 미리 알 수 없는 경우에 사용

  • map(int, input().split()) : 한 줄 입력받아 공백으로 나눈 문자열 리스트를 int형으로 변환
  • list() : 괄호안의 데이터를 리스트로 묶음
arr = list(map(int, input().split())
print(arr)

# 입력
>>> 1 2 3 4 5
# 결과
[1, 2, 3, 4, 5]

🔵 이어진 숫자를 한자리씩 나눠서 리스트에 저장: 문자열 리스트로 저장

  • input() : 한 줄을 읽어옴(구분 문자가 없다/ 문자열로 읽어옴)
print(input())               # 한 줄을 입력받아 그대로 출력

# 입력
>>> 12345
# 결과
12345
---------------------------------------------------------
arr = list(input())          # 한 줄을 입력받아 list 함수를 적용

# 입력
>>> 12345
# 결과
['1', '2', '3', '4', '5']

🔵 이어진 숫자를 한자리씩 나눠서 리스트에 저장 : 숫자형 리스트로 저장

map() 함수를 이용해서 문자열을 숫자로 변환한 후 list() 함수를 이용해서 리스트로 변환

arr = list(map(int, input()))    # map을 이용해서 문자열을 숫자로 변환
print(arr)

# 입력
>>> 12345
# 결과
[1, 2, 3, 4, 5]      

🔵 N행으로 이루어진 2차원 배열 입력받기

  • 리스트를 안에 리스트를 생성하면 반복문을 사용할 수 있음
  • arr = [반복내용 for _ in range(반복횟수)]
  • 이렇게 쓰면 반복횟수만큼 반복할 내용을 수행한다.
N = int(input())
arr = [list(map(int, input().split())) for _ in range(N)]
print(arr)

# 입력
>>> 3            # N 입력받기
>>> 1 2 3        # 공백으로 구분되어 총 3행이 입력
>>> 4 5 6        # N번을 반복하며 한 줄씩 읽고, 공백 문자로 나눠서 숫자형으로 반환
>>> 7 8 9        # 1차월 배열로 만들어 2차원 배열로 완성
# 결과
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]  # 2차원 배열로 출력

✔️ 파이썬에서 데이터 입력 부분에서 시간초과가 발생하지 않게 하는 방법

🟡 Standard Input

💡 input() 보다는, sys 라이브러리에서 제공하는 sys.stdin.readline()을 사용

백준에서 문제를 풀다보면 데이터 입력에서 input()을 사용하여 시간초과가 되는 경우가 있다. 그럴 때 input 대신 sys.stdin.readline을 사용하면 대부분의 경우에서 시간 초과를 방지할 수 있다.

Java에서는 SannerSystem.out.println 보다는 BufferedReader를 사용해야 하고,

Python에서는 input 대신 sys 라이브러리의 sys.stdin.readline()을 권장한다.

→ 두 입력 방식의 작동 과정을 통해 많은 양의 입출력을 시행할 경우 input() 함수가 더 느린 이유를 이해해보자.


🟡 input() Function

input() 함수의 경우 사용자의 입력을 읽어온 후, 아래와 같은 처리 과정을 거친다.

  1. 프롬프트로부터 사용자의 입력을 받음.
  2. 입력 받은 값 중에서, 개행문자 \n을 제거
  3. 해당 값을 문자열로 변경한 후, return

또한, input() 함수의 경우, 더 이상 입력이 주어지지 않을 때 EOFError를 띄운다.


🟡 sys.stdin Object

sys.stdin은 input() 함수와 달리 File Object → 하나의 객체

하단의 코드를 실행시켰을 경우, sys.stdin 객체의 속성을 열람할 수 있다.

dir(sys.stdin)
>>> ['_CHUNK_SIZE', '__class__', '__del__', '__delattr__', 
	 '__dict__', '__dir__', ..., 'write', 'writelines']

그리고 readline의 경우 sys.stdin 객체에서 지원하는 메소드이다.

또한 readlineEOF에 도달할 시 에러가 아닌 빈 문자열을 반환한다.

❗️ 주의 readline의 경우 개행문자 \n까지 받아온다.

이를 제거하고 싶다면 strip() 함수를 추가로 실행해주어야 한다.


🟡 가장 빠르게 동작하는 입력

  • input() 함수는 사용자의 입력을 받아 문자열로 변환시키는 과정이 필요
  • sys.stdin의 경우 사용자의 입력을 Buffer에 저장한 후 요청이 올때마다 읽음

→ 그렇기 때문에 sys.stdin.readline이 input() 함수보다 더 빠르게 동작

불필요한 전처리 과정 없이 바로 Buffer에서 한 줄씩 값을 읽어오기만 하면 된다.

  • sys.stdin.readline 메소드를 변수에 할당시키는 방법

→ 파이썬에서의 함수는 1급 객체(First-Class Object)로 취급

import sys

read = sys.stdin.readline
N = int(read())
data = [sum(map(int, read().split())) for _ in range(N)]

for num in data:
	print(num)

→ 보다 효율적으로 입출력 처리가 가능


🟡 Example of Code

💡 여러 케이스에 대한 다양한 입력 방식에 따른 코드를 안내

🟡 N개의 정수를 한 줄로 입력 받았을 경우

import sys

read = sys.stdin.readline
N, M, K = map(int,input().split())

read().split()을 통해 나온 list 내의 요소들을 int() 함수로 변환하여 최종적으로 나온 정수들을 순차적으로 변수에 저장하는 방식


🟡 N개의 정수를 한 줄로 입력 받아 List에 저장하는 경우

import sys

read = sys.stdin.readline
data = list(map(int, read().split()))

위의 방식과 거의 동일하지만 차이점이 있다면 list() 함수의 유무다

map() 함수는 map 객체를 리턴하기 때문에 이를 다시 list로 반환해주어야 한다.


🟡 N개의 정수를 여러 줄에 걸쳐 입력 받아 list에 저장하는 경우

import sys

read = sys.stdin.readline
N = int(read())
data = [int(read()) for _ in range(N)]

다른 방식으로 list 배열을 생성한 후 append() 함수를 통해 요소를 추가해도 가능

But, List Comprehension 기법을 사용하면 더 간결하게 코드를 작성할 수 있음.


🟡 N개의 문자열을 여러 줄에 걸쳐 입력 받아 list에 저장하는 경우

import sys

read = sys.stdin.readline
N = int(read())
data = [read().strip() for _ in range(N)]

대부분의 문자열 처리의 경우 개행문자 \n를 제거해야 하는 경우가 많은데 strip() 함수를 통해 문자열에 붙은 개행문자를 제거하면 된다.


🟡 N개의 정수를 여러 줄에 걸쳐 입력 받아 이차원 배열에 저장하는 경우

import sys

read = sys.stdin.readline
N = int(read())
arr = [list(map(int, read().split())) for _ in range(N)]

2차원 배열의 경우 그래프 문제를 풀기 위해 주어진 입력을 토대로 만드는 경우가 많다.

이 경우에도 List Comprehension 기법을 사용하여 한 줄로 2차원 배열 생성이 가능

✏️ Review

알고리즘 문제를 풀 때 항상 sys.stdin.readline()을 사용하였지만 그 원리에 대해서 공부를 하니 이해도가 확실히 상승한거 같다.

📝 Reference

https://velog.io/@rookieand/1-Python-%EC%BD%94%EB%94%A9-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%9E%85%EC%B6%9C%EB%A0%A5#-conclusion

profile
Welcome! This is cocoball world!

0개의 댓글