제로베이스 데이터 파트타임 스쿨 학습 일지 [25.04.28]

[강의 요약]

[Part 03. 자료구조&알고리즘 with Python_ Ch 02. 자료구조 문제풀이] 강의 수강

44_[연습문제] 튜플 (01)부터 48_[연습문제] 튜플 (05)까지 강의 수강하였음

🐢 100일 챌린지 🔥 : [▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰░                                       ] 43/100일 (43%)

글 작성하면서 들은 플리

 

 

 

 

[44_[연습문제] 튜플 (01)]

튜플은 고정된 데이터를 저장할 때 유용함

리스트로 변환하면 수정/추가 가능하고, 다시 튜플로 변환할 수 있음

▶ 코드 : 자주 접속하는 웹사이트 비번을 튜플에 저장

passwds = ('password1234', 'abc123', 'qwerty', 'letmein', 'welcome00')
print(f'passwds : {passwds}')

[출력 결과]

passwds : ('password1234', 'abc123', 'qwerty', 'letmein', 'welcome00')

 

 

▶ 실습 코드

먼저 3학년 총 학점, 평균 계산 및 4학년 목표 학점을 계산하는 코드를 작성

scores = ((3.7, 4.2), (2.9, 4.3), (4.1, 4.2))
total = 0

for s1 in scores:
    for s2 in s1:
        total += s2

total = round(total, 1)
avg = round((total / 6), 1)

print(f'3학년 총학점: {total}')
print(f'3학년 평균: {avg}')

[출력 결과]

3학년 총학점: 23.4
3학년 평균: 3.9

 

 

그다음 4학년 목표 학점, 한 학기 최소학점을 계산하는 코드를 작성

print('-'*60)

grade4TargetScore = round((4.0 * 8 - total), 1)
print(f'4학년 목표 총학점: {grade4TargetScore}')

minScore = round(grade4TargetScore / 2, 1)
print(f'4학년 한학기 최소학점: {minScore}')

[출력 결과]

------------------------------------------------------------
4학년 목표 총학점: 8.6
4학년 한학기 최소학점: 4.3

 

 

4학년 1학기 2학기 성적을 튜플로 추가하는 코드를 작성

scores = list(scores)  # 튜플 → 리스트 변환
scores.append((minScore, minScore))  # 4학년 1, 2학기 추가

print('-'*60)

scores = tuple(scores)  # 다시 튜플 변환
print(f'scores: {scores}')

[출력 결과]

------------------------------------------------------------
scores: ((3.7, 4.2), (2.9, 4.3), (4.1, 4.2), (4.3, 4.3))

 

 

 

[45_[연습문제] 튜플 (02)]

두 개의 튜플을 이용하여 합집합(중복 제거)과 교집합을 구해보는 코드를 구현할 수 있다.

합집합 : 중복 없이 두 튜플을 합쳐서 하나의 튜플로 만든 것

교집합 : 두 튜플 모두에 존재하는 공통 원소들만 추출한 것

주의해야 할 점은 튜플은 변경 불가이므로 리스트 변환 후 조작해야 한다는 것

▶ 코드

튜플을 리스트로 변환 후 합집합과 교집합을 구하는 코드를 작성

tuple1 = (1, 3, 2, 6, 12, 5, 7, 8)
tuple2 = (0, 5, 2, 9, 8, 6, 17, 3)

tempHap = list(tuple1)
tempGyo = list()

for n in tuple2:
    if n not in tempHap:
        tempHap.append(n)
    else:
        tempGyo.append(n)

tempHap = tuple(sorted(tempHap))
tempGyo = tuple(sorted(tempGyo))

print(f'합집합(중복X)\t : {tempHap}')
print(f'교집합\t\t : {tempGyo}')

[출력 결과]

합집합(중복X)	 : (0, 1, 2, 3, 5, 6, 7, 8, 9, 12, 17)
교집합		 : (2, 3, 5, 6, 8)

 

 

위 문제 다른 풀이 방식.

튜플을 이어인 후 직접 중복 제거 및 교집합 추출하는 코드 작성

tuple1 = (1, 3, 2, 6, 12, 5, 7, 8)
tuple2 = (0, 5, 2, 9, 8, 6, 17, 3)

tempHap = tuple1 + tuple2
print(f'tempHap : {tempHap}')

tempGyo = list()

tempHap = list(tempHap)
print(f'tempHap : {tempHap}')

for n in tempHap:
    if tempHap.count(n) > 1:
        tempGyo.append(n)
        tempHap.remove(n)

print(f'tempHap : {tempHap}')
print(f'합집합(중복X): {tuple(sorted(tempHap))}')

print(f'tempGyo : {tempGyo}')
print(f'교집합 : {tuple(sorted(tempGyo))}')

[출력 결과]

tempHap : (1, 3, 2, 6, 12, 5, 7, 8, 0, 5, 2, 9, 8, 6, 17, 3)
tempHap : [1, 3, 2, 6, 12, 5, 7, 8, 0, 5, 2, 9, 8, 6, 17, 3]
tempHap : [1, 2, 12, 7, 0, 9, 6, 17]
합집합(중복X): (0, 1, 2, 6, 7, 9, 12, 17)
tempGyo : [3, 5, 8, 2, 6, 8, 3]
교집합 : (2, 3, 3, 5, 6, 8, 8)

 

차이점이 뭘까?

결론부터 말하면 처음 방법이 교집합 결과를 더 깔끔하게 정리할 수 있다.

두 번째 방법은 교집합에 중복원소가 남기 때문에 최종 교집합 정리에는 추가 후처리가 필요할 수 있기 때문이다.

 

 

 

[46_[연습문제] 튜플 (03)]

튜플도 리스트처럼 슬라이싱할 수 있음

튜플의 최솟값, 최댓값을 찾고 인덱스도 구할 수 있음

▶ 코드

numbers = (8.7, 9.0, 9.1, 9.2, 8.6, 9.3, 7.9, 8.1, 8.3)

# 슬라이싱
print(f'numbers[:4] : {numbers[0:4]}')    # index 0~3
print(f'numbers[2:5] : {numbers[2:5]}')    # index 2~4
print(f'numbers[3:] : {numbers[3:]}')      # index 3~
print(f'numbers[2:-1] : {numbers[2:-1]}')  # index 2 ~ 뒤에서 두 번째 전까지
print(f'numbers[::3] : {numbers[::3]}')    # 전체에서 3칸씩 건너뛰기

# 최솟값/최댓값
print(f'최솟값 : {min(numbers)}')
print(f'최솟값 인덱스 : {numbers.index(min(numbers))}')

print(f'최댓값 : {max(numbers)}')
print(f'최댓값 인덱스 : {numbers.index(max(numbers))}')

[출력 결과]

numbers[:4] : (8.7, 9.0, 9.1, 9.2)
numbers[2:5] : (9.1, 9.2, 8.6)
numbers[3:] : (9.2, 8.6, 9.3, 7.9, 8.1, 8.3)
numbers[2:-1] : (9.1, 9.2, 8.6, 9.3, 7.9, 8.1)
numbers[::3] : (8.7, 9.2, 7.9)
최솟값 : 7.9
최솟값 인덱스 : 6
최댓값 : 9.3
최댓값 인덱스 : 5

 

 

▶ 코드

korScore = int(input('국어 점수 입력: '))
engScore = int(input('영어 점수 입력: '))
matScore = int(input('수학 점수 입력: '))
sciScore = int(input('과학 점수 입력: '))
hisScore = int(input('국사 점수 입력: '))

# 점수 저장
scores = (
    {'kor': korScore},
    {'eng': engScore},
    {'mat': matScore},
    {'sci': sciScore},
    {'his': hisScore}
)

print(f'scores: {scores}')

# 점수 → 학점 변환
for item in scores:
    for key in item.keys():
        if item[key] >= 90:
            item[key] = 'A'
        elif item[key] >= 80:
            item[key] = 'B'
        elif item[key] >= 70:
            item[key] = 'C'
        elif item[key] >= 60:
            item[key] = 'D'
        else:
            item[key] = 'F'

print(f'scores: {scores}')

[입력]

국어 점수 입력: 85
영어 점수 입력: 92
수학 점수 입력: 77
과학 점수 입력: 88
국사 점수 입력: 59

[출력 결과]

scores: ({'kor': 85}, {'eng': 92}, {'mat': 77}, {'sci': 88}, {'his': 59})
scores: ({'kor': 'B'}, {'eng': 'A'}, {'mat': 'C'}, {'sci': 'B'}, {'his': 'F'})

 

 

 

[47_[연습문제] 튜플 (04)]

강의자료 코드에서는 오름차순 코드만 포함되어 있어서,

내림차순은 개인적으로 추가했음

 

▶ 코드

[입력]

fruits = ({'수박':8}, {'포도':13}, {'참외':12}, {'사과':17}, {'자두':19}, {'자몽':15})
fruits = list(fruits)

cIdx = 0
nIdx = 1
eIdx = len(fruits) - 1

flag = True
while flag:
    curDic = fruits[cIdx]
    nextDic = fruits[nIdx]

    curDicCnt = list(curDic.values())[0]
    nextDicCnt = list(nextDic.values())[0]

    if nextDicCnt < curDicCnt:
        fruits.insert(cIdx, fruits.pop(nIdx))
        nIdx = cIdx + 1
        continue

    nIdx += 1
    if nIdx > eIdx:
        cIdx += 1
        nIdx = cIdx + 1
        if cIdx == 5:
            flag = False

print(tuple(fruits))

fruits는 여러 딕셔너리가 들어있는 튜플

리스트로 변환하여 인덱스별로 비교하면서 정렬

cIdx, nIdx를 이동하며 현재 값과 다음 값을 비교하고, 다음 값이 더 작으면 위치를 변경

모든 비교가 끝나면 오름차순으로 정렬된 튜플 출력. 끝

[출력 결과]

({'수박': 8}, {'참외': 12}, {'포도': 13}, {'자몽': 15}, {'사과': 17}, {'자두': 19})

 

 

내림차순으로도 정렬해서 출력해 보자.

fruits = ({'수박':8}, {'포도':13}, {'참외':12}, {'사과':17}, {'자두':19}, {'자몽':15})
fruits = list(fruits)

cIdx = 0
nIdx = 1
eIdx = len(fruits) - 1

flag = True
while flag:
    curDic = fruits[cIdx]
    nextDic = fruits[nIdx]

    curDicCnt = list(curDic.values())[0]
    nextDicCnt = list(nextDic.values())[0]

    if nextDicCnt < curDicCnt:
        fruits.insert(cIdx, fruits.pop(nIdx))
        nIdx = cIdx + 1
        continue

    nIdx += 1
    if nIdx > eIdx:
        cIdx += 1
        nIdx = cIdx + 1
        if cIdx == 5:
            flag = False

print(tuple(fruits))

오름차순에서는 if nextDicCnt < curDicCnt: 비교했지만

내림차순에서는 if nextDicCnt > curDicCnt: 로 비교방향만 반대로 바꿈

비교 방향 하나만 바꾸면 된다는 말이다.

그런데 sorted +_key 활용하는 방법으로도 정렬가능할듯함

[출력 결과]

({'수박': 8}, {'참외': 12}, {'포도': 13}, {'자몽': 15}, {'사과': 17}, {'자두': 19})

 



[48_[연습문제] 튜플 (05)]

▶ 코드

# 학급별 학생 수 데이터 (튜플 안에 딕셔너리)
studentCnt = (
    {'cls01':18},
    {'cls02':21},
    {'cls03':20},
    {'cls04':19},
    {'cls05':22},
    {'cls06':20},
    {'cls07':23},
    {'cls08':17}
)

totalCnt = 0
minStdCnt = 0
minCls = ''
maxStdCnt = 0
maxCls = ''
deviation = []

# 데이터 처리
for idx, dic in enumerate(studentCnt):
    for k, v in dic.items():
        totalCnt += v

        if idx == 0 or minStdCnt > v:
            minStdCnt = v
            minCls = k

        if maxStdCnt < v:
            maxStdCnt = v
            maxCls = k

print(f'전체 학생 수: {totalCnt}명')

avgCnt = totalCnt / len(studentCnt)
print(f'평균 학생 수: {round(avgCnt, 2)}명')

print(f'학생 수가 가장 적은 학급: {minCls}({minStdCnt}명)')
print(f'학생 수가 가장 많은 학급: {maxCls}({maxStdCnt}명)')

for idx, dic in enumerate(studentCnt):
    for k, v in dic.items():
        deviation.append({k: round(v - avgCnt, 2)})

print(f'학급별 학생 편차: {deviation}')

전체 학생 수 : 각 학급 학생 수 모두 더하기

평균 학생 수 : 전체 학생 수 ÷ 학급 수

최소/최대 학생 수 학급 찾기 : 반복문 안에서 비교

학급별 편차 계산 : 각 학습 학생 수 - 평균값

튜플은 딕셔너리 접근 후 key, value를 분리해서 활용

[출력 결과]

전체 학생 수: 160명
평균 학생 수: 20.0명
학생 수가 가장 적은 학급: cls08(17명)
학생 수가 가장 많은 학급: cls07(23명)
학급별 학생 편차: [{'cls01': -2.0}, {'cls02': 1.0}, {'cls03': 0.0}, {'cls04': -1.0}, {'cls05': 2.0}, {'cls06': 0.0}, {'cls07': 3.0}, {'cls08': -3.0}]

 

 

 

[나의 생각 정리]

튜플은 수정, 추가, 삭제가 불가능해서 데이터 보호가 필요한 경우 사용하면 좋다.

리스트처럼 인덱싱, 슬라이싱, 반복문 활용이 가능해서 다루기 편하다.

대신 값을 바꿔야 할 경우에는 리스트로 변환 후 수정해야 하는 번거로움이 있다.

합집합, 교집합 구현도 가능은 하지만 리스트처럼 자유롭진 않아서 귀찮다.

 

 

[적용점]

변경할 필요 없는 데이터는 무조건 튜플로 저장

수정이 필요하면 리스트 변환 후 작업

중복 제거, 합집합/교집합 처리 시 set 자료형을 사용하자

 

 

 

“이 글은 제로베이스 데이터 스쿨 주 3일반 강의 자료 일부를 발췌하여 작성되었습니다.”