Do it! 자료구조와 함께 배우는 알고리즘 입문(파이썬) :: DAY 04
enumerate()
enumerate() 함수는 인덱스와 원소를 짝지어 튜플로 꺼내는 내장 함수
x = ['John', 'George', 'Paul', 'Ringo']
for i in range(len(x)):
print(f'x[{i}] = {x[i]}')
for i, name in enumerate(x):
print(f'x[{i}] = {name}')
# 출력 결과 동일
# x[0] = John
# x[1] = George
# x[2] = Paul
# x[3] = Ringo
# 리스트의 모든 원소를 enumerate() 함수로 스캔
for i, name in enumerate(x, 1):
print(f'{i}번째 = {name}')
# 리스트의 모든 원소를 스캔하기(인덱스 값 사용하지 않음)
for i in x:
print(i)
리스트 역순으로 정렬
리스트(x) 자체를 역순으로 정렬하려면 list형의 reverse() 함수를 사용
x.reverse()
역순으로 정렬한 리스트 생성
reversed() 함수를 호출하는 reversed(x)는 x의 원소를 역순으로 정렬하는 이터러블 객체를 생성한다
즉 x의 원소를 역순으로 꺼내는 이터레이터를 반환하는 것
따라서 reversed() 함수가 반환하는 이터러블 객체를 list() 함수에 넘기고 새로운 리스트를 생성해야 한다
y = list(reversed())
sort 랑 sorted처럼 같은 것인데 ed 붙여져 있는 것의 차이가 항상 궁금했다
정확한 차이를 모르니까 코드를 작성할 때 이렇게 했다가 안되면 이렇게 하고 오류가 안 나는 것을 사용했었다
책을 보고도 크게 와닿지 않아서 찾아보고 정리해보면
reverse는 뒤집어진 값을 저장할 뿐 리턴하지 않고 reversed는 뒤집어진 값을 리턴한다
따라서 reversed는 리턴 값이 필요할 때 사용하며 리턴값이 있기 때문에 새로운 리스트를 생성해야 하는 것이다
기수와 서수
기수는 수를 나타내는 데 기초가 되며 10진법에서 0~9까지 정수를 말한다.
서수는 사물의 순서를 나타낸다
기수는 1, 2, 3....이고 서수는 첫째, 둘째, 셋째...
# 기수로 변환하는 프로그램
def card_conv(x:int, r:int) -> str:
d = ''
dchar = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
while x > 0:
d += dchar[x%r]
x //= r
return d[::-1]
if __name__ == '__main__':
print('10진수를 n진수로 변환합니다.')
while True:
no = int(input('변환할 값으로 음이 아닌 정수를 입력'))
if no > 0:
break
while True:
cd = int(input('어떤 진수로 변환? : ')
if 2 <= cd <= 36:
break
print(f'{cd}진수로는 {card_conv(no, cd)}입니다.')
retry = input("한 번 더 변환? (Y or N) : ")
if retry in {'N', 'n'}:
break
def card_conv(x:int, r:int) -> str:
d = ''
dchar = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
n = len(str(x))
print(f'{r:2} | {x:{n}d}')
while x > 0:
print(' +'+(n+2)*'-')
if x//r:
print(f'{r:2} | {x//r:{n}d} ... {x%r}')
else:
print(f' {x // r:{n}d} ... {x%r}')
d += dchar [X%r]
x //= r
return d[::-1]
위의 코드가 조금 이해가 안 간다
나중에 다시 한번 보기
함수 사이에 인수 주고받기
def sum_1ton(n):
s = 0
while n > 0:
s += n
n -= 1
return s
x = int(input('x의 값을 입력하세요.: '))
print(f'1부터 {x}까지 정수의 합은 {sum_1ton(x)}입니다.'})
함수가 실행 과정에서 매개변수 n의 값은 5, 4, 3...으로 감소한다
매개변수 n으로 실제 인수 x의 값이 복사되었다 (x)
파이썬에서는 매개변수에 실제 인수가 대입되는데 대입에서 복사되는 것은 그림과 같이 값이 아니라 참조하는 곳이다
그래서 n과 x가 참조하는 곳이 같다
마지막 함수가 종료할 때는 그림과 같이 n은 0을 참조한다
함수의 실행 시작 시점에서 매개변수는 실제 인수와 같은 객체를 참조한다
인수가 이뮤터블 : 함수 안에서 매개변수의 값을 변경하면 다른 객체를 생성하고 그 객체에 대한 참조로 업데이트, 매개변수의 값을 변경해도 호출하는 쪽의 실제 인수에는 영향을 주지 않는다
인수가 뮤터블: 함수 안에서 매개변수의 값을 변경하면 객체 자체를 업데이트, 매개변수의 값을 변경하면 호출하는 쪽의 실제 인수는 값이 변경
파이썬에서 인수 전달은 실제 인수의 객체에 대한 참조를 값으로 전달하여 매개변수에 대입되는 방식
다른 프로그래밍 언어에서는 실제 인수의 값을 매개변수에 복사하는 값에 의한 호출을 사용하거나, (call by value)
실제 인수의 참조를 매개변수에 복사하여 매개변수가 실제 인수와 같아지는 참조에 의한 호출을 사용한다(call by reference)
소수 나열하기
이거 되게 많이 해 본 알고리즘 문제이다
그런데,,,
평소에는 어떻게 풀지 와 답이 나오면 넘겼는데 책에서는 시간을 줄여주는 방법이 나와서 좋았다
어차피 2보다 큰 짝수는 소수가 아니니까 홀수만 계산한다던지 등등
앞으로는 알고리즘 문제를 풀면서 이런 생각을 좀 해야겠다
counter = 0
for n in range(2, 1001):
for i in range(2, n):
counter += 1
if n % i == 0:
break
else:
print(n)
print(f'나눗셈을 실행한 횟수: {counter}')
counter = 0
ptr = 0
prime = [None]*500
prime[ptr] = 2
ptr += 1
for n in range(3, 1001, 2): # 홀수만으 대상으로 설정
for i in range(1, ptr): # 이미 찾은 소수로 나눔
counter += 1
if n % prime[i] == 0:
break
else:
prime[ptr] = n #소수로 배열에 등록
ptr += 1
for i in range(ptr):
print(prime[i])
print(f'나눗셈을 실행한 횟수: {counter}')
counter = 0
ptr = 0
prime = [None]*500
prime[ptr] = 2
ptr += 1
prime[ptr] = 3
ptr += 1
for n in range(5, 1001, 2):
i = 1
while (prime[i]*prime[i] <= n:
counter += 2
if n % prime[i] == 0:
break
i += 1
else:
prime[ptr] = n
ptr += 1
counter += 1
for i in range(ptr):
print(prime[i])
print(f'곱셈과 나눗셈을 실행한 횟수: {counter}')
n=15일 때 안 맞는 것 같은데... 내가 코드 순서를 제대로 이해 못 한 것 같다
주말에 다시 한번 보기
어쨌든 결론?
같은 결과를 얻을 수 있는 알고리즘은 여러 개일 수 있다
빠른 알고리즘은 많은 메모리를 요구한다
리스트의 원소와 복사
copy()
- 리스트를 복사한 후 원솟값을 변경하면 복사된 원 솟값까지 변경될 수 있기 때문에 조심해서 사용
- 리스트의 얕은 복사 (shallow copy)
- 새로운 객체로 복사할 때 객체가 참조 자료형의 멤버를 포함, 참조값만 복사
deepcopy()
- 깊은 복사 (deep copy)
- 참조값뿐만 아니라 참조하는 객체 자체를 복사, 객체가 갖는 모든 멤버를 복사
import copy
x = [[1,2,3], [4,5,6]]]
y = copy.deepcopy(x)
z = x.copy()
x[0][1] = 9
print(x)
# [[1,9,3], [4,5,6]]]
print(y)
# [[1,2,3], [4,5,6]]] y 배열은 영향을 받지 않음
print(z)
# [[1,9,3], [4,5,6]]]