맥주를 먹고 그만 월요일이 되어버렸어요.

자 (1)에서 배웠던 테크닉으로 여러 형태의 입력을 받아볼거에요.

이번 시간에는 배열을 인풋으로 받는 방법에 관해서 종류별로 가볍게 설명드리고 넘어가려고 해요.

C, C++, Java 사용자들은 배열을 인풋으로 받기전에 먼저 배열은 선언해두는 것이 익숙합니다.

하지만 python의 경우 배열 선언이 매우 귀찮을 뿐아니라, 고정된 크기로 메모리를 잡아두는 것이 상당히 어렵습니다.

따라서, 그냥 input을 받으면서 동시에 input을 받은 값으로 초기화하는 코드를 자주 사용하게 됩니다.

이것도 마찬가지로 손쉽게 map으로 해결할 수 있는데, 각 예제로 설명 드릴께요.

1차원 배열을 인풋으로 받기

1차원 배열을 선언할 수 있는 문제를 먼저 하나 가져와볼께요.

X보다 작은 수라고하는 문제입니다.

https://www.acmicpc.net/problem/10871

X보다 작은 수

입력 서술

첫째 줄에 N과 X가 주어진다. (1 ≤ N, X ≤ 10,000)
둘째 줄에 수열 A를 이루는 정수 N개가 주어진다. 주어지는 정수는 모두 1보다 크거나 같고, 10,000보다 작거나 같은 정수이다.

입력 예제1

10 5
1 10 4 9 2 3 8 5 7 6

입력 받는 코드

N, X = map(int, input().split(" "))
ARR = list(map(int, input().split(" ")))

이 코드를 실행했을 때, 위의 예제1을 받으면 아래처럼 저장됩니다.

사족 - 왜 굳이 map함수 이후 list형으로 변환을?

왜 굳이 map함수를 사용한 후에 다시 list 형으로 변환을 해줬을까요?

사실 map 함수의 결과물인 map object는 iteration을 돌 수 있지만,

임의의 인덱스로 접근이 불가능합니다. map함수의 리턴형은 list가 아닙니다!

즉, [0] [1] [2] 와같은 인덱스로 접근하는 것이 불가능해요.

따라서 list 함수로 형을 변환해줘야만 접근이 가능하다는 것이죠!

아래 코드를 실행하면 에러가 발생할 거에요 한번 테스트 해보세요!

test_var = map(int, "1234")
print(test_var[1])

그렇기 때문에 map으로 생성한 것을 리스트와 같이 사용하려면 list로 캐스팅해줘야 합니다.

하지만 1번째 줄처럼 map에서 나온 오브젝트를 각 변수에 바로 나눠서 담는 경우는 굳이 map을 list로 캐스팅해주실 필요는 없습니다.

2차원 배열을 인풋으로 받기

입력 사이에 구분자가 있는 경우 - 종이의 개수

종이의 개수라는 문제로 예제를 들어볼까해요.

https://www.acmicpc.net/problem/1780

입력 서술

첫째 줄에 N(1 ≤ N ≤ 37, N은 3k 꼴)이 주어진다. 다음 N개의 줄에는 N개의 정수로 행렬이 주어진다.

입력 예제 1

9
0 0 0 1 1 1 -1 -1 -1
0 0 0 1 1 1 -1 -1 -1
0 0 0 1 1 1 -1 -1 -1
1 1 1 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0
0 1 -1 0 1 -1 0 1 -1
0 -1 1 0 1 -1 0 1 -1
0 1 -1 1 0 -1 0 1 -1

입력 받는 코드

N = int(input())
PAPER = [list(map(int, input().split(" "))) for i in range(N)]

이 코드를 실행했을 때, 위의 입력 예제1을 받으면 아래처럼 저장됩니다.

저번 포스팅에서 한줄로 들어온 데이터를 입력 받는 법을 배웠었죠.

이를 활용하면 위와 같은 코드 한줄로 2차원 배열의 입력을 받을 수 있습니다.

구분자가 space bar이고, 이 구분자를 배열을 생성하면서 N번 동시에 받은 거죠.

다른 언어에 비해서 이런 부분은 확실히 편하게 입력을 받을 수 있는 것 같습니다.

입력 사이에 스페이스가 없는 경우 - 알고스팟

이러한 형태의 문제들이 많지는 않습니다. 하지만 분명이 존재하고 가끔 생각이 안돌아갈때 어떻게 입력을 받아야하지... 라는 고민을 하게되곤 해요.

알고스팟으로 그 예제를 들어볼까해요.

https://www.acmicpc.net/problem/1261

입력 서술

첫째 줄에 미로의 크기를 나타내는 가로 크기 M, 세로 크기 N (1 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 미로의 상태를 나타내는 숫자 0과 1이 주어진다. 0은 빈 방을 의미하고, 1은 벽을 의미한다.
(1, 1)과 (N, M)은 항상 뚫려있다.

입력 예제 1

3 3
011
111
110

자 이 문제의 입력은 기존에 배웠던 원리로 매우 간단하게 처리 할 수 있어요.

입력 받는 코드

N, M = map(int, input().split(" "))
MIRO = [list(map(int, input())) for i in range(N)]

이 코드를 실행했을 때, 위의 입력 예제 1을 받으면 아래처럼 저장됩니다!

이 코드를 보시면

MIRO = [list(map(int, input())) for i in range(N)]

이번에는 input()에 split이 없어요. str 자료형은 그 자체로 list처럼 생각하셔도 무방해요. 

사실상 "011" 이면 ["0", "1", "1"] 과 같다고 할 수 있죠.

스페이스바가 없는 입력을 분리하고 싶다면, split 없이 위와 같은 코드로 입력을 받아서 처리할 수 있어요.

배열 선언하기

거의 대부분의 언어들에서 배열을 선언하는 것에 많은 코드를 필요로 하지 않습니다.

하지만 이 나쁜 python은 배열 선언하기를 더럽게 복잡하게 만들어 뒀습니다.

numpy라도 쓸수 있게 해준다면 정말 행복할 텐데, 어림도 없습니다.

대부분의 코딩 테스트에서는 numpy를 지원하지 않습니다.

배열 선언 코드

INIT = -1
# ML러들이 좋아하는 변수명
W = row     # 행
H = column  # 렬
C = channel # 3차원!
B = batch   # 4차원! 

D1 = [INIT for j in range(W)]
D2 = [[INIT for i in range(W)] for j in range(H)]
D3 = [[[INIT for k in range(W)] for i in range(H)] for j in range(C)]
D4 = [[[[INIT for l in range(W)] for k in range(H)] for i in range(C)] for j in range(B)]

맞아요. 왕도가 없습니다... 여러분이 알고 있는 이 방법이 최적입니다.

이건 죄송할 따름이네요. 순수 파이썬으로는 이 방법말고 좋은 방법을 찾지 못했습니다.

손에 익으시면 호다닥 작성 할 수 있을 겁니다.

마무리

python은 멋진 언어입니다. 배열 빼고는요.

배열은 numpy가 없으면 정말 사용하기 귀찮기 그지없습니다.

python 4쯤에는 배열을 미리 할당할 수 있는 좋은 방법이 제안되었으면 하네요.

다음 글로 마무리를 지을 예정이에요.

다음 글에서는 python의 내장함수를 이용한 여러 잡기술들을 포스팅하고자 합니다.

+ Recent posts