프로그래밍 문제를 풀다 보면, 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리스트를 생성할 때는,
을 사용하시는 것이 가장 좋다고 이해하셔도 될 듯 합니다.
출처-https://stackoverflow.com/questions/13157961/2d-array-of-zeros
'파이썬 > 파이썬 문법(심화)' 카테고리의 다른 글
[WIP]대한민국에서 가장 자세한 f-string 가이드 (0) | 2023.05.26 |
---|---|
[잡지식] 문자열 연결에 "+"를 사용하지 마세요! (0) | 2023.02.19 |
(Python) 약수 구하기.(시간 복잡도:$O(\sqrt{n})$) (0) | 2022.12.26 |
2진수로 표현한 숫자의 1의 개수 세기. (0) | 2022.10.27 |
2차원 리스트를 회전시키기 (0) | 2022.10.25 |