[1] do-while
while True:
# 실행문
if 조건:
break
파이썬에서 do while 문은 while True 로 따라할 수 있다.
꼭 조건문과 break 를 써서 무한 루프를 만들지 말자.
[2] 리스트 복사
original = [1, 2, 3]
# 단순 복사
copy1 = original
# 얕은 복사
copy2-1 = original.copy()
copy2-2 = original[:]
# 깊은 복사
copy3 = copy.deepcopy(original)
1. 단순 복사
original 과 copy1 은 같은 주소값을 가리킨다. 단지 이름만 다를 뿐이다.
즉, original 을 변경하거나 copy1 을 변경할 경우 서로에게 동시에 영향을 준다.
2. 얕은 복사
copy2 를 수정해도 original 에는 반영되지 않는다.
하지만 copy2 의 특정 값을 수정하면 original 의 값도 같이 수정될 수 있다.
왜냐하면 얕은 복사는 새로운 리스트 객체를 생성하지만,
그 리스트 안에 있는 값들은 원래 리스트의 참조를 그대로 가져오기 때문이다.
그래서 리스트 안에 가변 객체가 들어있으면 같이 수정될 수 있다.
* 가변객체 (mutable object)
- 내부 값을 변경하면 같은 객체가 수정된다.
- 리스트(list), 딕셔너리(dict), 집합(set), 바이트 배열(bytearray)
* 불변 객체 (immutable object)
- 수정하려고 하면 항상 새로운 객체가 생서된다.
- 숫자형(int, float), 문자열(str), 튜플(tuple), frozenset, 불리언(bool)
# 원본 리스트: 2차원 리스트 (내부에 가변 객체인 리스트가 포함되어 있음)
original = [[1, 2], [3, 4]]
# 얕은 복사: 원본 리스트의 탑 레벨만 복사됨 (내부 리스트는 참조만 복사)
# copy[0]은 original[0]과 같은 객체를 참조함
copy = original[:]
copy[0][0] = 99 # 내부 리스트의 값을 수정
print(original) # [[99, 2], [3, 4]] (원본도 영향을 받음)
# 탑 레벨 리스트의 첫 번째 요소를 새 리스트로 대체
copy[0] = [5, 6] # copy[0]만 새로운 리스트을 참조하도록 변경
print(original) # [[99, 2], [3, 4]] (원본은 영향을 받지 않음)
# 원본 리스트: 숫자로만 이루어진 1차원 리스트 (숫자는 불변 객체임)
original_list = [1, 2, 3]
# 얕은 복사: 원본 리스트의 모든 요소가 새 리스트에 복사됨 (값만 복사)
# shallow_copy와 original_list는 독립적임
shallow_copy = original_list[:]
shallow_copy[0] = 99 # 복사본의 첫 번째 요소를 변경
print(original_list) # [1, 2, 3] (원본은 영향을 받지 않음)
3. 깊은 복사
불변 객체는 그대로 가져오고, 가변 객체는 새로운 공간에 값을 복사하여 가져온다.
원본 리스트와 복사본 리스트가 완전히 다른 객체가 된다.
그래서 어느 한 쪽을 수정해도 서로 영향을 주지 않는다.
단, 완벽한 복사를 위해 새로운 곳을 생성하기 때문에, 시간이 오래 걸리고 메모리 소모도 크다.
그래서 상황에 따라 얕은 복사와 깊은 복사를 가려 사용해야 한다.
* 문제 풀이
# 값이 50보다 크거나 같은 짝수라면 2로 나누고, 50보다 작은 홀수라면 2를 곱하고 다시 1을 더합니다.
# arr(x) = arr(x + 1)인 x 중 가장 작은 값 반환
def compare_50_x(arr):
# debugging & tracking states
all_result = [arr[:]]
i = 0
while True:
for j, n in enumerate(arr):
if n >= 50 and not n % 2:
arr[j] = n // 2
elif n < 50 and n % 2:
arr[j] = n * 2 + 1
all_result.append(arr[:])
if all_result[i] == all_result[i + 1]:
break
else:
i += 1
return i
'''
[[1, 2, 3, 100, 99, 98], [3, 2, 7, 50, 99, 49]]
[[1, 2, 3, 100, 99, 98], [3, 2, 7, 50, 99, 49], [7, 2, 15, 25, 99, 99]]
[[1, 2, 3, 100, 99, 98], [3, 2, 7, 50, 99, 49], [7, 2, 15, 25, 99, 99], [15, 2, 31, 51, 99, 99]]
[[1, 2, 3, 100, 99, 98], [3, 2, 7, 50, 99, 49], [7, 2, 15, 25, 99, 99], [15, 2, 31, 51, 99, 99], [31, 2, 63, 51, 99, 99]]
[[1, 2, 3, 100, 99, 98], [3, 2, 7, 50, 99, 49], [7, 2, 15, 25, 99, 99], [15, 2, 31, 51, 99, 99], [31, 2, 63, 51, 99, 99], [63, 2, 63, 51, 99, 99]]
[[1, 2, 3, 100, 99, 98], [3, 2, 7, 50, 99, 49], [7, 2, 15, 25, 99, 99], [15, 2, 31, 51, 99, 99], [31, 2, 63, 51, 99, 99], [63, 2, 63, 51, 99, 99], [63, 2, 63, 51, 99, 99]]
5
'''
나는 반복문의 결과물을 배열에 모두 담고 그 결과물로 비교하는 방식으로 문제를 풀었다.
그러나 이런 방식은 메모리를 너무 잡아먹고 불필요하게 모든 과정을 기록해서 비효율적이다.
# efficiency & simplicity
answer = 0
old = arr
while True:
new = []
for i in old:
if i >= 50 and i % 2 == 0:
i = i / 2
elif i < 50 and i % 2 == 1:
i = i * 2 + 1
new.append(int(i))
if old == new:
break
else:
old = new
answer += 1
return answer
이렇게, 이전 것과 현재 것만 변수에 담은 뒤, 값을 비교하고, 다른 경우 값을 바꿔치기 해서 진행하면
비교적 메모리 효율이 좋고 로직도 단순해서 좋다.
쓸 데 없는 기록을 지양하고 목표 행위에만 초점을 맞추자.
https://www.freecodecamp.org/korean/news/pythonyi-do-whilemun-banbogmun-yeje/
https://black-hair.tistory.com/49