자료구조란?
컨테니어 자료형이라고 하고, 이러한 컨테이너 자료형의 데이터 구조를 자료구조라고 한다.

- 리스트 안의 값은 언제든지 바꿀 수 있다
- 튜플은 리스트와 비슷하지만, 값을 바꿀 수 없다
- 딕셔너리는 key:value로 이루어져 있다
- 셋트는 중복된 데이터가 허용되지 않는다
student1 = '홍길동'
student2 = '박찬호'
student3 = '이용규'
students = ['홍길동', '박찬호', '이용규']
print(students)
print(type(students))

students = ('홍길동', '박찬호', '이용규')
print(students)
print(type(students))

scores = {'kor':95, 'eng':80, 'mat':100}
print(scores)
print(type(scores))

allSales = {100, 200, 500, 200}
print(allSales) # 중복은 하나의 데이터만 표시
print(type(allSales))

# 반복문으로 데이터 하나하나 출력 할 수 있다
for student in students:
print(student)

리스트(List)란?
리스트 선언
student = '홍길동'
print(student)
print(type(student))
students = ['홍길동', '박찬호', '이용규'] # []를 이용해 선언; '홍길동' <-- 아이템(요소) 라고 부른다
print(students) # 리스트는 대괄호로 출력됨
print(type(students))
numbers = [10, 20, 30]
print(numbers)
print(type(numbers))
strs = [3.14, '십', [20, 'one']] # 여러 데이터 형태나 또 다른 컨테이너 자료형 같이 저장 가능
print(strs)
print(type(strs))

인덱스(Index)

아이템 조회
students = ['홍길동', '박찬호', '이용규']
print(students[0])
print(students[1])
print(students[2])

print(students[3]) # 범위 밖의 인덱스 번호로 조회시 오류

numbers = [1,2,3,4]
print(type(numbers)) # 데이터 타입: 리스트
print(numbers[1])
print(type(numbers[1])) # 데이터 타입: 개별 아이템 본연의 데이터 타입

아이템 개수

students = ['홍길동', '박찬호', '이용규']
print(len(students)) # len() 파이썬의 내장함수

(1) len()를 이용한 조회
for i in range(len(students)): # 아이템 개수만큼 반복
print('i : {}'.format(i))
print('students[{}] : {}'.format(i, students[i]))

(2) len()를 이용한 조회
str = 'Hello Python'
print(len(str))

for문을 이용한 조회
cars = ['그랜저','소나타','말리부','카니발']
for i in range(len(cars)): # 인덱스를 이용한 접근
print(cars[i])
print('-'*10)
for car in cars: # 아이템을 바로 이용한 접근
print(car)

for문을 이용한 내부 리스트 조회
studentsCnts = [[1,19], [2,20], [3,22], [4,18], [5,21]] # 리스트 안의 리스트
for i in range(len(studentsCnts)):
print('{}학급 학생수: {}'.format(studentsCnts[i][0], studentsCnts[i][1])) # 이렇게도 가능하지만
print('-'*10)
# 아래 방법이 더 편할 수 있다
# 리스트 안의 리스트 하나씩 내려온다
for classNo, cnt in studentsCnts: # 변수를 2개를 주면, 예를 들어, [1,19]안의 classNo -> 1 참조, cnt -> 19 참조
print('{}학급 학생수: {}'.format(classNo, cnt))

for문을 이용한 조회
minScore = 60
scores = [
['국어',58],
['영어',77],
['수학',89],
['과학',99],
['국사',50]
]
# index 이용
for item in scores:
if item[1] < minScore:
print('과락 과목: {}, 점수: {}'.format(item[0], item[1]))
print('-'*10)
# iterable 객체 이용
for subject, score in scores: # iterable 객체인 socres를 for문에, 그 안의 subject, score라는 지역변수
if score < minScore:
print('과락 과목: {}, 점수: {}'.format(subject, score))
print('-'*10)
# continue 이용
for subject, score in scores:
if score >= minScore: continue # 이상인 경우 출력을 하지 않고 다음 반복문 실행
print('과락 과목: {}, 점수: {}'.format(subject, score))

while문을 이용한 조회
cars = ['그랜저','소나타','말리부','카니발']
n = 0
while n < len(cars): # n이 리스트의 아이템 개수 보다 작다면
print(cars[n])
n += 1 # n에 1씩 추가되다 마지막 반복이 끝나면 n은 리스트의 아이템 개수보다 많아지게 되며, 반복문 중단
print('-'*10)
n = 0
flag = True
while flag: # flag가 True인 동안 반복문 실행
print(cars[n])
n += 1 # n에 1씩 추가
if n == len(cars): # n이 리스트의 아이템 개수와 같아지면
flag = False # flag가 False로 바뀌게 되며 반복문 중단
print('-'*10)
n = 0
while True:
print(cars[n])
n += 1
if n == len(cars):
break

while문을 이용한 조회
minScore = 60
scores = [
['국어',58],
['영어',77],
['수학',89],
['과학',99],
['국사',50]
]
n = 0
while n < len(scores):
if scores[n][1] < minScore: # 각 리스트([n])의 점수([1]) 값이 minScore보다 작다면
print('과락 과목: {}, 점수: {}'.format(scores[n][0], scores[n][1])) # 과목과 점수 출력
n += 1 # 무한반복을 방지하기 위해 1씩 추가
print('-'*10)
n = 0
while n < len(scores):
if scores[n][1] >= minScore: # 각 리스트의 점수 값이 minScore보다 크다면
n += 1
continue # 다음 반복으로 넘어가라
# 위 조건에 맞지 않다면 (점수가 minScore보다 큰 것이 아니라면)
print('과락 과목: {}, 점수: {}'.format(scores[n][0], scores[n][1]))
n += 1

enumerate()
sports = ['농구','수구','축구','마라톤']
for i in range(len(sports)):
print('{} : {}'.format(i, sports[i]))
print('-'*10)
for idx, value in enumerate(sports):
print('{} : {}'.format(idx, value))

str = "Hello Python"
for idx, value in enumerate(str):
print(idx, value)

# 가장 좋아하는 스포츠를 입력했을 때 몇 번째에 있는지 출력
sports = ['농구','수구','축구','마라톤']
favoriteSport = input('가장 좋아하는 스포츠 입력: ')
for idx, value in enumerate(sports):
if value == favoriteSport:
bestSportIdx = idx + 1 # index 번호는 0부터 시작하니 "~번째"로 출력하기 위해 +1
print('{}은(는) {}번째에 있습니다.'.format(favoriteSport, bestSportIdx))

# 메세지를 입력했을 때, 공백은 몇 개있는지 출력
message = input('메시지 입력:')
cnt = 0
for idx, value in enumerate(message):
if value == ' ':
cnt += 1
print('공백 개수: {}'.format(cnt))

아이템 추가하기
students = ['홍길동', '박찬호', '이용규', '박승철']
print(students)
print('numbers:', len(students))
print('last index:', students.index('박승철'))
students.append('강호동')
print(students)
print('numbers:', len(students))
print('last index:', students.index('강호동'))

# 가족 구성원의 나이가 아래와 같을 때 새로 태어난 동생을 리스트에 추가하기
myFamilyAge = [['아빠', 40], ['엄마', 38], ['나', 9]]
myFamilyAge.append(['동생', 1])
for name, age in myFamilyAge:
print('{}의 나이: {}'.format(name, age))

특정 위치에 아이템 추가하기
students = ['홍길동', '박찬호', '이용규', '박승철']
print(students)
print('numbers:', len(students))
print('last index:', students.index('박승철'))
# insert(a, b): a는 끼어들 자리/인덱스, b는 끼워넣을 값
students.insert(3, '강호동') # 3번 인덱스, 즉, 4번째 자리에 '강호동' 끼워넣기
print(students)
print('numbers:', len(students))
print('last index:', students.index('박승철'))

words = ['I', 'a', 'boy.']
words.insert(1, 'am')
for word in words:
print('{} '.format(word), end='') # end='' : 자동 개행 방지

numbers = [1,3,6,11,45,54,62,74,85]
inputNumber = int(input('숫자 입력:'))
insertIdx = 0
for idx, number in enumerate(numbers):
print(idx, number)
if insertIdx == 0 and inputNumber < number: # 입력한 숫자가 현재 반복문 실행중인 number보다 작다면, 해당 number의 index 번호를 저장
insertIdx = idx # 만약 입력한 숫자가 더 크다면, 다음 반복문 진행
# 입력한 숫자가 가장 작다면, inx는 0에 머무를테고,
# 다른 number보다 큰 경우엔 더 큰 다른 number가 있기 전까지 반복문 돌다가
if insertIdx == 0: # 만약 끝까지 없다면, 가장 큰 수라는 뜻이니 가장 뒤의 index 위치에 추가
numbers.append(inputNumber)
print(numbers)
else:
numbers.insert(insertIdx, inputNumber) # 만야 가장 큰 수가 아니라면, 처음 또는 중간에 추가가 될 것이다.
print(numbers)

마지막 인덱스 아이템 삭제
특정 위치의/인덱스의 아이템 삭제
students = ['홍길동', '박찬호', '이용규', '강호동', '박승철']
print(students)
print('numbers:', len(students))
print('last index:', students.index('박승철'))
students.pop(3) # index 3인 '강호동' 삭제
print(students)
print('numbers:', len(students))
print('last index:', students.index('박승철'))

playerScores = [9.5, 8.9, 9.2, 8.8, 9.0]
print(playerScores)
minScore = 0; maxScore = 0
minScoreIdx = 0; maxScoreIdx = 0
# 최저점수
for idx, score in enumerate(playerScores):
if idx == 0 or minScore > score: # 처음 반복문이 실행되면 idx == 0이 유효하니, minSCoreIdx엔 0이 저장되고, minScore에는 9.5가 저장 (첫번째이니)
minScoreIdx = idx # 다음 점수가 내려오고 minscore인 9.5와 비교하여 작으면 그 수가 이젠 minscore가 되고...
minScore = score # 이렇게 하나씩 비교하면 minscoreindex와 minscore값이 정해질 것이다
print('minScore: {}, minScoreIdx: {}'.format(minScore, minScoreIdx))
# 최저점수 삭제
playerScores.pop(minScoreIdx) # 아래 반복문 까지 끝나고 지우게 되면 index가 틀어질 수도 있으니 최저점수 반복문 끝나면 바로 지우자
# 최고점수
for idx, score in enumerate(playerScores):
if maxScore < score: # 모든 스코어가 0 보다 크니 일단 처음 내려온 스코어(9.5)가 maxScore에 저당되고, index도 maxsocreidx에 저장되고
maxScoreIdx = idx # 다음 점수가 내려오고 9.5와 비교하고 더 크다면 새로운 maxscore가 될 테고,...
maxScore = score # 이런식으로 반복 비교하며 최고 점수를 구할 수 있다
print('maxScore: {}, maxScoreIdx: {}'.format(maxScore, maxScoreIdx))
# 최고점수 삭제
playerScores.pop(maxScoreIdx)
print(playerScores)

특정 아이템 삭제
students = ['홍길동', '박찬호', '이용규', '강호동', '박승철']
print(students)
print('numbers:', len(students))
print('last index:', students.index('박승철'))
students.remove('강호동') # '강호동' 삭제
print(students)
print('numbers:', len(students))
print('last index:', students.index('박승철'))

2개 이상의 아이템 삭제
students = ['홍길동', '박찬호', '이용규', '강호동', '박승철', '강호동', '강호동','강호동']
print(students)
#print('numbers:', len(students))
#print('last index:', students.index('박승철'))
students.remove('강호동') # '강호동' 삭제
print(students)
#print('numbers:', len(students))
#print('last index:', students.index('박승철'))
# --> 뒤에 있는 '강호동'은 삭제되지 않았다.
# 반복문을 사용하여 다 없어질 때까지 삭제해 나가자
while ('강호동' in students): # stduents에 '강호동'이 있다면 True라는 조건이니, 강호동이 다 삭제되면 False가 되며 반복문 끝
students.remove('강호동') # '강호동' 삭제
print(students)

# 과목을 입력하면 과목 리스트에서 해당 과목이 지워지도록 만들기
subjects = ['국어', '영어', '수학', '과학', '국사']
print('시험 과목표: {}'.format(subjects))
removeSubject = input('삭제 과목명 입력: ')
while(removeSubject in subjects):
subjects.remove(removeSubject)
print('시험 과목표: {}'.format(subjects))

리스트 연결(확장)
group1 = ['홍길동', '박찬호', '이용규']
group2 = ['강호동', '박승철', '김지은']
print('group1:',group1)
print('group2:',group2)
group1.extend(group2)
print('group1:',group1)
print('group2:',group2)
print('-'*30)
group1 = ['홍길동', '박찬호', '이용규']
group2 = ['강호동', '박승철', '김지은']
result = group1 + group2
print('new group:',result)
print('group1:',group1)
print('group2:',group2)

# 나와 친구가 좋아하는 번호를 합치되 번호가 중복되지 않게 하는 프로그램 만들기
myNum = [1,3,5,6,7]
friendNum = [2,3,5,8,10]
print('myNum:',myNum)
print('friendNum:',friendNum)
# 일단 내 번호와 친구 번호를 합치기
addList = myNum+friendNum
print('addList:',addList)
result = [] # 번호를 하나씩 담을 빈 리스트
for number in addList: # 반복문이 돌아가면서 번호가 하나씩 내려가고
if number not in result: # 만약 리스트에 없는 새로운 번호라면 리스트에 추가
result.append(number) # 이렇게 되면 새로운 번호만 추가 되기 때문에, 중복이 없어진다.
print('result:', result) # 최종적으로 정리된 번호 리스트 출력

리스트 정렬
students = ['홍길동', '박찬호', '이용규', '강호동', '박승철','김지은']
print(students)
students.sort() # 여기서 리스트가 정렬이 된 것이다
print(students) # 그 리스트를 출력해서 확인하면 정렬이 되어 있는 것을 볼 수 있다.
students.sort(reverse=True)
print(students)

numbers = [1, 5, 7, 2, 9, 3]
print(numbers)
numbers.sort()
print(numbers)
numbers.sort(reverse=True)
print(numbers)

scores = [9.5, 8.9, 9.2, 9.8, 8.8, 9.0]
print(scores)
# 최저, 최고 점수 삭제
scores.sort() # 오름차순 정렬
print(scores)
scores.pop(0) # 최저 점수 삭제
scores.pop(len(scores) - 1) # 최고 점수 삭제; 전체 길이에서 1을 뺀 것이 가장 뒤 index이니 최고 점수
print(scores)
# 최저, 최고 점수 삭제 후 총점과 평균 출력
sum = 0
avg = 0
for score in scores:
sum += score # sum에 score이 계속 더해져 총점이 저장된다
avg = sum / len(scores) # (총점/남은 점수의 전체 길이) --> 평균
print('총점:', round(sum, 2))
print('평균:', round(avg, 2))

리스트의 아이템 순서 뒤집기
students = ['홍길동', '박찬호', '이용규', '강호동', '박승철','김지은']
print(students)
students.reverse()
print(students)
numbers = [1, 5, 7, 2, 9, 3]
print(numbers)
numbers.reverse()
print(numbers)

# 다음은 전쟁에서 사용되는 암호이다. 암호를 해독하는 프로그램을 만들자.
'''
암호: 27156231
해독: 13326125157214
'''
# 일단 암호를 뒤집은 후, 첫 두 숫자의 곱한 값이 그 뒤에 붙은 것이다.
secret = '27156231'
secretList = []
solvedList = ''
for cha in secret:
secretList.append(int(cha)) # 일단 암호를 하나씩 잘라서 리스트에 담고
print(secretList)
secretList.reverse() # 리스트 안의 순서 뒤집기
print(secretList) # 순서가 뒤바뀐 리스트 출력
# 뒤집은 순서에서 각 앞의 두 숫자를 곱하여 두 숫자 뒤에 붙여넣기
val = secretList[0] * secretList[1] # index 0, 1 값의 곱셈을 그 뒤인 세번째 위치(index 2)에 추가
secretList.insert(2, val)
print(secretList)
val = secretList[3] * secretList[4] # 앞에 val이 추가되었으니, 앞 index 다음의 index 숫자를 입력
secretList.insert(5, val)
print(secretList)
val = secretList[6] * secretList[7]
secretList.insert(8, val)
print(secretList)
val = secretList[9] * secretList[10]
secretList.insert(11, val)
print(secretList)

리스트 슬라이싱
students = ['홍길동', '박찬호', '이용규', '강호동', '박승철','김지은']
print(students)
print(students[2:4])
print(students[:4]) # 처음부터 3번 index까지
print(students[2:]) # 2번 index부터 끝까지
print(students[2:-2]) # '-'를 사용하면 뒤에서 부터 따진다
print(students[-5:-2])
numbers = [1, 5, 7, 2, 9, 3]
print(numbers)
print(numbers[2:4])
print(numbers[:4])
print(numbers[2:])
print(numbers[2:-2])
print(numbers[-5:-2])

문자열 슬라이싱
str = 'abcdefghijklmnopqrstuvwxyz'
print(len(str))
print(str)
print(str[2:4])
print(str[:4])
print(str[2:])
print(str[2:-2])
print(str[-5:-2])

슬라이싱 단계 설정
numbers = [1, 5, 7, 2, 9, 3]
print(numbers)
print(numbers[2:-2])
print(numbers[2:-2:2]) # 세번째에 있는 숫자는 단곌를 의미; 몇 칸씩
print(numbers[:-2:2])
print(numbers[::2])

슬라이싱을 이용한 아이템 변경
students = ['홍길동', '박찬호', '이용규', '강호동', '박승철','김지은']
print(students)
students[1:4] = ['park chanho', 'lee yonggyu', 'gang hodong'] # 슬라이싱과 할당연산자 사용; 해당되는 위치의 값이 바뀐다
print(students)

slice() 함수
students = ['홍길동', '박찬호', '이용규', '강호동', '박승철','김지은']
print(students)
print(students[slice(2, 4)])
print(students[slice(4)]) # index 3까지; 시작값이 생략 된 것
print(students[slice(2, len(students))]) # 2부터 끝까지
print(students[slice(2, len(students)-2)]) # 2부터 끝에서 2번째 까지
print(students[slice(len(students)-5, len(students)-2)]) # 1~4

리스트 곱셈 연산
students = ['홍길동', '박찬호', '이용규']
print(students)
students_m = students*2
print(students_m)
numbers = [1, 5, 7]
print(numbers)
numbers_m = numbers*2
print(numbers_m)

아이템 위치 찾기
students = ['홍길동', '박찬호', '이용규', '강호동', '박승철','김지은']
print(students)
searchIdx = students.index('강호동')
print(searchIdx)
searchIdx = students.index('강호동',2,6) # index 2 ~ 6앞 사이(범위)에서 '강호동' index찾기
print(searchIdx)

# 1부터 10까지의 정수가 중복되지 않고 섞여 있을 때, 행운의 숫자 7의 위치를 찾기
import random
sampleList = random.sample(range(1, 11), 10) # 1부터 10까지, 총 10개의 정수를 중복되지 않게 생성
selectIdx = int(input('숫자 7의 위치 입력:')) # 내가 생각하는 7의 index 위치
searchIdx = sampleList.index(7) # 랜덤하게 정해진 7의 index 위치
if searchIdx == selectIdx: # 만약 내가 생각한 7의 index 위치가 랜덤하게 정해진 위치와 같다면
print('빙고') # 위치를 찾았다!
else:
print('Wrong') # 틀림
print('sampleList:', sampleList) # 랜덤하게 나온 숫자
print('searchIdx:', searchIdx) # 실제 숫자 7의 위치

특정 아이템의 개수 알아내기
students = ['홍길동', '박찬호', '이용규', '강호동', '박승철', '김지은', '강호동']
print(students)
searchCnt = students.count('강호동')
print(searchCnt)

특정 아이템 삭제
students = ['홍길동', '박찬호', '이용규', '강호동', '박승철', '김지은', '강호동']
print(students)
del students[3]
print(students) # 앞에 있던 '강호동' 삭제됨

students = ['홍길동', '박찬호', '이용규', '강호동', '박승철', '김지은', '강호동']
print(students)
del students[1:4] # 슬라이싱으로 범위로 삭제할 수도 있다
print(students)

# 하루 동안 헌혈을 진행 한 후 혈액형 별 개수를 파악하는 프로그램 만들기
import random
types = ['A', 'B', 'AB', 'O']
todayData = [] # 100개의 혈액형 정보가 저장될 변수
typeCnt = []
for i in range(100):
type = types[random.randrange(len(types))] # len(types): 0,1,2,3 --> 0,1,2,3 중 랜덤하게 types[' ']에 들어가
todayData.append(type) # indexing이 되며, 랜덤한 혈액형 값을 todayData에 하나씩 추가; ->100개
print(todayData) # 만들어진 100개의 혈액형 리스트
print('todayData length:', len(todayData)) # 총 길이/개수
for type in types: # 혈애형 종류 이름/값을 하나씩 반복문을 돌려
print('{}형\t: {}개'.format(type, todayData.count(type))) # 각가 todayData에 몇 개씩 있는지 count하여 출력
