CodingTest

코딩테스트 준비 - 파이썬 해시 정리

취업하고싶다! 2023. 10. 30. 15:09

딕셔너리로 접근해서 푸는 문제는 '해시' 유형으로 dictionary 자료구조를 얼마나 잘 쓸 수 있냐를 묻는 문제

해시 문제를 풀기위해 알아야 할 것들을 정리해봄

 

enumerate란?

iterable한 자료형을 인자로 넣으면 (인덱스,값) 형태의 enumerate 객체를 반환
for문과 사용할 수도 있고, 리스트나 딕셔너리 형태로 만들 수도 있음

헷갈리지 말고 기억할 것: 인덱스가 먼저고 값이 그 다음인 형태

 

[파이썬이 권장하지 않는 for문 사용 방식]

for i in range(len(arr)):
	print(arr[i])

[파이썬이 권장하는 방식]

for item in arr:
	print(item)

위 두 가지 방식의 차이를 이해했다면 enumerate의 쓰임이 어디에 있는지도 대강 감이 옴
for문 사용 시 현재 몇 번째 반복문인지(for문의 i)를 알아야 할 때가 많은데, 이때 이 목적을 위해 for i in range(len(arr))를 사용하는 게 아니라, enumerate를 활용하는 것!

 

eumerate를 사용한 for문

arr = ['a','ab','abc']
for idx,val in enumerate(arr):
	print(idx,val)
    
# result
0 a
1 ab
2 abc

enumerate 객체들을 담은 리스트나 딕셔너리를 만들 수도 있음

 

 

zip이란?

여러 개의 iterable한 객체를 인자로 받아 인덱스별로 값을 zip해줌
한 엔트리에 대한 정보가 여러 개의 배열에 나눠 담겨져 있을 때 사용하면 좋음

numbers = [1,2,3]
letters = ['a','ab','abc']

# zip 사용
for pair in zip(numbers,letters):
	print(pair)

# zip 사용 X
for i in range(i):
	print(numbers[i], letters[i])

for문을 돌 때 배열에 인덱스로 접근하는 걸 지양할 것!

 

문자열에서도 사용 가능하고, zip한 결과를 딕셔너리에 담을 수도 있음

# 문자열 사용 예시
str1 = "abc"
str2 = "123"
str3 = "ABC"
for first,second,third in zip(str1,str2,str3):
	print(first,second,third)
# result
a 1 A
b 2 B
c 3 C
# 딕셔너리 변환
numbers = [1,2,3]
letters = ['a','ab','abc']

dic = dict(zip(letters,numbers))

참고로 인자로 넘겨준 iterable 객체의 길이가 서로 다르면 길이가 짧은 객체 길이에 맞춰 pair가 생성되고 나머지는 버려짐

 

 

딕셔너리란?

특정 값을 검색해야 하는 문제에서 쓰면 유용
인덱스가 아니라 '특정 값'을 찾아야 하는 경우 리스트는 O(N)의 시간이 걸림

우리가 가지고 있는 정보가 인덱스 밖에 없기 때문에 인덱스로 모든 배열을 순회해야 하는데, 딕셔너리는 값을 알고 있으면 O(1)으로 해당 값에 접근할 수 있음

 

딕셔너리 컴프리헨션

  • 인덱스와 값으로 딕셔너리 만들기 - enumerate
names = ['James', 'Judy', 'Jin']
dic = {v:i for i,v in enumerate(names)}
# {'James':0, 'Judy':1, 'Jin':2}
  • 두 가지 값으로 딕셔너리 만들기 - zip
names = ['James', 'Judy', 'Jin']
height = [180, 160, 170]
dic = {name:height for name,height in zip(names,height)}
# {'James': 180, 'Judy': 160, 'Jin': 170}
  • 특정 조건을 만족할 때에만 딕셔너리에 추가하기
    ex 키가 170 이상인 사람만 딕셔너리에 추가
dic = {name:height for name,height in zip(names,height) if height>=170}
# {'James': 180, 'Jin': 170}

 

값 검색하기

두 가지 방식이 있음
1. dic[val]
2. dic.get(val)

딕셔너리에 없는 값에 접근했을 때 1번 방법은 오류를 내고 코드를 종료시킴
2번 방법은 None을 리턴. 따라서 값의 유무를 검색해야 할 때는 1번 방법이 아닌 2번 방법을 사용해야 함!

가령 아래와 같은 패턴. None은 꼭 대문자로 시작해야 함에 유의!
반대는 is not None 임

names = ['James', 'Judy', 'Jin']

for name in names:
    if dic.get(name) is None:
    	# 존재하지 않는 key값에 대한 처리
    elif dic.get(name) is not None:
    	# 존재하는 key값에 대한 처리

# in, not in 을 활용해도 값 유무에 따른 분기를 해줄 수 있다.
for name in names:
    if name in dic:
    	# 존재하지 않는 key값에 대한 처리
    elif name not in dic:
    	# 존재하는 key값에 대한 처리

혹은 자바스크립트의 || 처럼 딕셔너리에 key가 존재할 때는 상응하는 value값을, 존재하지 않으면 내가 설정한 기본값을 리턴하도록 할 수도 있다.

dic = {'James': 180, 'Judy': 160, 'Jin': 170}
users = ['June','James','Judy','Jack']
for user in names:
	print(dic.get(name,0))
# result
...
0
180
160
0

 

 

Counter 객체

Collections 모듈에 속한 클래스
데이터 별로 개수를 셀 때 사용

>>> from collections import Counter
>>> str = 'hello world'
>>> print(Counter(str))
Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
>>> print(Counter(str).most_common(2))
[('l', 3), ('o', 2)]

>>> arr = ['Kim', 'Kim', 'Lee', 'Kim', 'Park', 'Kown', 'Lee']
>>> print(Counter(arr))
Counter({'Kim': 3, 'Lee': 2, 'Park': 1, 'Kown': 1})