본문 바로가기
SSAFY

[수업기록] 데이터 구조(2)

by 주니코니 2024. 7. 23.

240723 파이썬반

 

1. 비시퀀스 데이터 구조

 

1) 딕셔너리 메서드

-딕셔너리란 : 고유한 항목(key)들의 정렬되지 않은(순서X) 컬렉션

D.clear() #딕셔너리 D의 모든 키/값 쌍을 제거 #list 메서드 clear와 동일

D.get(key[,default]) #키 k에 연결된 값을 반환(키가 없으면 none 혹은 default값 반환!!!!!!!!!!)
# 예제
person = {'name': 'Matt', 'age': 25}
print(person.get('name')) #Matt
print(person.get('country')) # None
print(person.get('country','unknown')) #key만약 없음 unknown 반환해주세요 #unknown
print(person['country']) #keyerror : 'country'

print(person.get('name')) #Matt
person.get('name') #'Matt'




.keys()
#예제
person = {'name': 'Matt', 'age': 25} 
print(person.keys()) #dict_keys(['name', 'age']) #출력형태보고 당황않기, 눈치껏 해결해도됨 리스트처럼 생겼으니 반복해서 빼볼까?
for item in person.keys():
    print(item) #name #age


.values()
#예제
person = {'name': 'Matt', 'age': 25}
print(person.values()) #dict_values(['Matt', 25])
for item in person.values():
    print(item) #Matt #25
    

.items()
# 예제
person = {'name': 'Matt', 'age': 25}
print(person.items()) #dict_items([('name', 'Matt'), ('age', 25)])
for key, value in person.items(): #tuple 변수 두개로 언패킹
    print(key) #('name', 'Matt') #('age', 25)
    print(value) #name #Matt #age #25
    
    
.pop(key[,default]) #리스트 pop과 전혀연관없음
#키를 제거하고, 연결됐던 값 반환
#없으면 에러나, default 반환
#예제
person = {'name': 'Matte', 'age': 25}
print(person.pop('age')) #25
print(person) #{'name': 'Matte'}
print(person.pop('country',None)) #None
# print(person.pop('country')) #KeyError: 'country'


.setdefault(key[,default])
#해당 키 조회시 없음 default와 연결한 키를 딕셔너리에 추가, default 반환
#예제
person = {'name': 'Matt', 'age': 25}
print(person.setdefault('country','KOREA')) #KOREA
print(person) #{'name': 'Matt', 'age': 25, 'country': 'KOREA'}
#장점 : 조건문 생략가능
# 예제 2
k = (1,2,3,'A')

my_dict.setdefault(k,'변수로도 키 설정 가능')
print(my_dict)  #(1, 2, 3, 'A'): '변수로도 키 설정 가능'}추가 되어 있음




.update([other]) #갱신 #기존 키는 덮어씀
person = {'name': 'Matt', 'age': 25}
other_person = {'name': 'Jane', 'gender': 'Female'}
person.update(other_person)
print(person) #{'name': 'Jane', 'age': 25, 'gender': 'Female'}

person.update(age=30, country='korea')
print(person) #{'name': 'Jane', 'age': 30, 'gender': 'Female', 'country': 'korea'}

 

# 다음코드는 복사(깊은/얕은)가 될까?
a ={} 
b =  {'name':'Sam'}

a.update(b)
print(a) #{'name': 'Sam'}

b['name'] = 'Harry'
print(a) #{'name': 'Sam'}
#놉

 

2) set : 고유한 항목들의 정렬되지 않은 컬렉션

- 주의사항 : 

a = {} #딕셔너리

b = set() # 빈 셋 #세트는 밀렸어..

s.add(x) 항목 x추가, 이미 x가 있다면 변화 없음
#예제
my_set = {'a', 'b', 'c', 1, 2, 3}
my_set.add(4)
print(my_set) # set1 = {0, 1, 2, 3, 4} #4가 끝에 들어간 게 아님!! 임의로 들어감(매번 다름)
#재실행시 {1, 2, 3, 'b', 4, 'c', 'a'}


# clear
my_set = {'a', 'b', 'c', 1, 2, 3}
my_set.clear()
print(my_set) #{}로 출력안됨 #dict에 밀림.. # set()로 출력됨



s.remove(x) 항목 x 제거, 항목 x 없다면 key error
# remove
my_set = {'a', 'b', 'c', 1, 2, 3}
my_set.remove(2) 
print(my_set)#{1, 3, 'b', 'c', 'a'}
my_set.remove(10)
print(my_set) #KeyError: 10


# discard
my_set = {'a', 'b', 'c', 1, 2, 3}
my_set.discard(2)
print(my_set) #{1, 3, 'b', 'c', 'a'}
my_set.discard(10) #에러있으면 pass함 아무것도출력안됨 #반환값은 none
print(my_set)


# update(iterable) # list의 extend(+=)와 유사
my_set = {'a', 'b', 'c', 1, 2, 3}
my_set.update([12,3])
print(my_set) #{1, 2, 3, 'b', 'c', 12, 'a'}


#집합 메서드
set1.difference(set2) # 연산자 : set1-set2
set1.intersection(set2) #연산자 : set2&set2
set1.issubet(2) # 연산자 : set 1<= set2
set1.isuperset(set2) #연산자  set1 >= set2
set1.union(set2) # set1 | set2
#예제
print(set1.difference(set2)) #{0, 2, 4}
print(set1.intersection(set2)) #{1,3}
print(set1.issubset(set2)) #다 포함되니?(일치)  #False
print(set3.issubset(set1)) #True
print(set1.issuperset(set2)) #False
print(set1.union(set2)) #{0, 1, 2, 3, 4, 5, 7, 9} #어라라 # 그러나 정렬아님

 

 

 

2. 해시 테이블 

해시 함수를 사용해서 반환한 해시 값을 색인(index, 정수)으로 삼아 키와 데이터(value)를 저장하는 자료구조

'데이터 검색이 매우 빠름'

 

해시함수는 파이썬이 재실행될 때마다 갱신됨 - 해시 함수 내용 구조 바뀜 -> john smith라는 key의 위치가 늘 바뀐다

*주피터 노트북 : 파이썬 재실행x, 환경(해시함수) 유지, 재실행하려면 restart 누를 것

*py 파일 : 재실행 ㅇㅇ

*키가 해시 함수를 통해 임의를 위치를 받는다  

 

 

set의 요소 & dictionary는 해시함수를 통해 구해진 해시값들 (해시) 테이블에 저장됨

=> set과 dict 중복 허용 x, 바로 검색 가능 

=> 해시테이블 : 순서있는 거 XXX

# 정수
my_set = {3, 2, 1, 9, 100, 4, 87, 39, 10, 52}
# print(my_set.pop()) # 1
# print(my_set.pop()) # 2
# print(my_set.pop()) # 3 
# print(my_set.pop()) # 100
# print(my_set.pop())
# print(my_set.pop())
# print(my_set.pop())
# print(my_set.pop())
# print(my_set.pop())
# print(my_set.pop())
# print(my_set)
#매번 순서대로 빠지네? 왜일까 : 파이썬의 해시함수는 정수만 들어갔을 때와 문자열 들어갔을 때가 다르다
#왜일까 : 일을 덜 하려고~!
#정수값이 들어왔는데 또 정수값이 들어온다면 비효율적이라 판단
#정수는 정수 자체가 반환됨
#정수 : 순서있어보이나 실제 순서가 부여된건X




# 문자열 #문자열 : 실행시마다 결과 변경
my_str_set = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
print(my_str_set.pop())
print(my_str_set.pop())
print(my_str_set.pop())
print(my_str_set.pop())
print(my_str_set.pop())

print(hash(1))
print(hash(1)) #1(정수) 계속 같은 주소값
print(hash('a'))
print(hash('a'))

print(hash(1))
print(hash(1.0))
print(hash('1'))
print(hash((1, 2, 3)))

# TypeError: unhashable type: 'list'
# print(hash((1, 2, [3, 4])))
# TypeError: unhashable type: 'list'
# print(hash([1, 2, 3]))
# TypeError: unhashable type: 'list'
# my_set = {[1, 2, 3], 1, 2, 3, 4, 5}
# TypeError: unhashable type: 'set'
# my_dict = {{3, 2}: 'a'}

 

 

정리 

-set의 pop : 임의의 요소 제거 후 반환

=> 실행할때마다 다른 요소를 얻는다는 의미에서 무작위(랜덤)가 아닌 임의라는 의미

=> pop, 정수에서 순서가 있어보이는 이유


3. BNF 표기법 : 문서상으로 존재하는 문법

-파이썬은 정확히 말하면 EBNF 표기법

-서로 다른 프로그래밍 언어, 문서상에서는 통일을 하자~

[] : 선택적 요소

{} : 0번 이상 반복

() : 그룹화 


수업보충

set, dictionary

# set
fruits = ['사과','사과','포도','귤']
fruits_set = set(fruits)
fruits_set = {f for f in fruits}

#어떤 요소가 출력될지 알 수 없음
for f in fruits_set:
    print(f)
#%%
fruits = ['사과','포도','귤']

nums = [100,300,50]
fruit_dict = {k:v for k,v in zip(fruits,nums)}
print(fruit_dict)

for key in fruit_dict:
    print(key, fruit_dict[key])
    
for val in fruit_dict.values():
    print(val)
    
for key,val in fruit_dict.items():
    print(key,val)
#딕셔너리와 리스트
score_dict = {'국어':[],'수학':[]}
score_dict['국어'].append(60)
print(score_dict) #key가 있는경우

#키가 없는 경우 리스트에 값넣기
# score_dict['영어'].append(50) #KeyError: '영어'
score_dict.setdefault('영어',[]).append(50)
print(score_dict)
# setdefault : 딕셔너리에 키가 존재하면 해당 키의 값 반환
# 키 존재안함 키 새로 만들고 지정된 기본값 할당 후 반환까지


#안정적으로 답 가져올 때 좋음
score_dict.get('영어',[])
# get 키가 존재하지 않은 경우 지정된 기본값을 반환
# 기본값 지정안하면 NONE

#setdefault가 없었다면?
#과학점수를 리스트에 추가
if '과학'  in score_dict:
    score_dict['과학'].append(30)
    
else:
    score_dict['과학'] = [30]
    
    
#%%
# defaultdict : 일반 딕셔너리와 달리 
# 존재하지 않는 키에 접근할 때 기본값을 반환
from collections import defaultdict
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(list) #리스트 반환
for k, v in s:
    d[k].append(v)

sorted(d.items())

#과일 갯수
fruits = ['사과','바나나','바나나']
fruit_dict = defaultdict(int) # 기본값 0 
for f in fruits:
    fruit_dict[f]  += 1
print(fruit_dict)