본문 바로가기
파이썬/파이썬 문법(심화)

0으로 초기화된 2-차원 리스트 생성하기.

by soypablo 2022. 6. 28.

프로그래밍 문제를 풀다 보면, 0으로 초기화된 2차원 리스트를 만들어야 할 때가 종종 있다.

여러가지 방법이 있겠지만, 안 좋은 예 2가지와 좋은 예 한가지를 소개한다.

예시1(좋음)

#시간이 오래걸리는 경우
N = 10 ** 4
arr = [[0] * N for _ in range(N)]

예시2(시간이 느림)

#시간이 오래걸리는 경우
N = 10 ** 4
arr = [[0 for _ in range(N)] for _ in range(N)]

 

예시3(예상하지 못한 결과가 발생함)

#참조를 잘못한 예
N = 10 ** 4
arr =  [[0] * N] * N

 

 

먼저 간단하게, time라이브러리를 이용하여 시간을 측정해보자.

 

예시1(좋음)

#time 라이브러리 임포트
import time
#생성 전 시간 변수저장
t0 = time.time()
N = 10 ** 4
arr = [[0] * N for _ in range(N)]
#생성 후 시간을 변수에 저장
t1 = time.time()
#생성 후 시간 - 생성 전 시간 출력
print(f"{t1 - t0:.2f}초 소요")

>>>

0.55초 소요

 

예시2(시간이 느림)

#time 라이브러리 임포트
import time
#생성 전 시간 변수저장
t0 = time.time()
N = 10 ** 4
arr = [[0 for _ in range(N)]for _ in range(N)]
#생성 후 시간을 변수에 저장
t1 = time.time()
#생성 후 시간 - 생성 전 시간 출력
print(f"{t1 - t0:.2f}초 소요")

>>>

2.16초 소요

시간차이가 약 4배 정도 남을 알 수 있다. 만약 N의 크기가 커진다면 이 격차가 더 벌어질 것이다.

예시3(예상치 못한 결과 발생)

 

import time
t0 = time.time()
N = 10 ** 4
arr = [[0] * N] * N
t1 = time.time()
print(f"{t1 - t0:.2f}초 소요")

>>>

0.00초 소요

 

예시3의 경우,  소수점2자리 까지 계산하였을 때, 0.00초로 매우 짧은 시간에 리스트를 생성하였다.

그러나, 문제는 리스트의 값을 변경하였을 때, 문제가 생긴다.

예시1(좋음)

N = 10
arr = [[0] * N for _ in range(N)]
arr[0][0] = 1
print(arr)

>>>

[[1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

첫번째 요소만 정확히 변경 되었음.

 

예시3(예상치 못한 결과 발생)

N = 10
arr = [[0] * N] * N
arr[0][0] = 1
print(arr)

>>>

[[1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

다음과 같이, 2중 리스트의 첫번째 리스트에서, 첫번째 요소만 1로 변경하였는데도 나머지 리스트의 첫번째 요소가 1로 변경된 것을 확인 할 수 있다.

 

이러한 결과가 발생하는 이유는?

2중리스트안에서, 2~10번째 리스트가, 첫번째 리스트를 참조하여 생성되었기 때문입니다.

즉 얕은 복사를 통해 리스트가 생성된 것이기 때문에 이러한 결과가 발생한 것입니다.

파이썬 공식 문서의 얕은 복사와 깊은복사의 설명입니다.

  • 얕은 복사와 깊은 복사의 차이점은복합 객체(리스트 또는 클래스 인스턴스들과 같은 다른 객체를 포함한 객체)에만 유효합니다.
  • 얕은 복사는 새로운 복합 객체를 만들고,(가능한 범위까지) 원본 객체를 가리키는 참조를 새로운 복합 객체에 삽입합니다.
  • 얕은 복사는 새로운 복합 객체를 만들고,(가능한 범위까지) 원본 객체를 가리키는 참조를 새로운 복합 객체에 삽입합니다.

더 자세한 내용이 궁금하시면, https://docs.python.org/ko/3/library/copy.html copy함수의 설명 문서를 참고하시면 도움이 될 것 같습니다.

 

결론은 N*N리스트를 생성할 때는,

arr = [[0] * N for _ in range(N)]

을 사용하시는 것이 가장 좋다고 이해하셔도 될 듯 합니다.

 

출처-https://stackoverflow.com/questions/13157961/2d-array-of-zeros