python을 한참 익히는 중이지만,
내가 어떤 알고리즘을 짜는 데에 있어 필요한,
정말 웬만한 것들은 모두 다 자체적으로 지원을 해 주는 것 같다.
이번 글에서 다루게 될 collections 또한 그 중 하나이다.
collections를 사용하게 된 곳은 "완주하지 못한 선수"를 찾아내는 문제에서였다.
마라톤 경기를 한다고 가정하였을 때,
참가자 목록이 주어지고,
완주한 사람들의 목록이 주어지게 된다.
이 때, 참가자 목록에는 있지만 완주한 사람들 목록에는 없는 사람,
즉 마라톤 경기에서 완주하지 못한 사람은 누구인지를 찾아내는 문제였다.
def check_not_completed_runner(participants, completions):
#participants는 참가자 목록 ['Chris', 'Lina', 'Andy', 'Miller', 'Chris']
#참가자 목록은 동명이인이 존재할 수 있다.
#completions는 완주자 목록 ['Chris', 'Lina', 'Andy', 'Miller']
위의 예시에서 찾아야 하는 정답은 'Chris'이다.
참가자 목록에서는 'Chris'라는 사람이 두 명이지만,
완주자 목록에서는 한 명 밖에 없기 때문이다.
결국 완주하지 못한 사람을 찾으려면,
참가자 목록에 존재하는 이름을 기준으로 몇 번이나 같은 이름의 선수가 존재하는지 세고,
완주자 목록에서 각 이름이 몇 번이나 들어있는지를 세어서 비교하면 되는 것이다.
따라서, 위에 작성한 문장과 똑같은 흐름으로 코딩을 해 보았다.
def solution(participant, completion):
answer = ''
for runner in completion:
runnerIndex = participant.index(runner)
participant.pop(runnerIndex)
answer = participant[0]
return answer
완주자 목록을 순회하면서 조회한 선수 이름을
참가자 목록에 몇 번째로 존재하는지 확인하고,
참가자 목록에서 해당 선수를 삭제해버렸다.
이런 식으로 진행하다보면, 결국 나중에는 한 사람만 남게 되고
남은 한 사람이 완주하지 못한 선수이다.
이렇게 풀이가 가능했던 이유는 문제를 제시할 때 완주하지 못한 사람이 단 한 명이라는 전제가 있었기 때문이다.
하지만 이것은 맨 처음 의사코드로 작성한 흐름과는 사뭇 다른 전개이다.
정말로 의사코드와 같은 흐름을 가지려면 아래와 같이 작성하면 될 것이다.
import collections
def solution(participant, completion):
answer = collections.Counter(participant) - collections.Counter(completion)
return list(answer.keys())[0]
collections의 사용은 아래의 원리와 같이 작동한다.
어떤 string 또는 list가 주어졌을 때,
해당 타입을 이루는 원소들을 확인하고
몇 개나 있는지 알아서 세어준다.
1. count string
먼저, Counter를 사용하지 않고 직접 세주는 경우이다.
def countLetters(word):
counter = {}
for letter in word:
if letter not in counter:
counter[letter] = 0
counter[letter] += 1
return counter
counteLetters('sangwoo')
# {'o': 2, 's': 1, 'a': 1, 'n': 1, 'g': 1, 'w': 1
직접 함수를 구현하면 위와 같이 할 수 있지만,
내장된 collections.Counter를 사용하여도 동일한 결과를 얻을 수 있다.
2. count list
list 내에 존재하는 원소들의 개수를 세어준다.
값이 중복되는 원소의 체크에서 유용하게 사용할 수 있다.
from collections import Counter
print(Counter(['a','b','c','d','a']))
# Counter({'a': 2, 'b': 1, 'c': 1, 'd': 1})
3. Counter 결과값 간의 연산
Counter 함수를 사용해서 얻어낸 결과물 dict는 서로 연산이 가능하다.
first = Counter([1,2,3,4,5])
second = Counter([9,3,1,3])
print(first - second)
# Counter({2: 1, 4: 1, 5: 1})
# first Counter에서 second Counter와 동일한 key를 가지는 원소에 대해서는, 해당하는 second의 개수만큼 빠진 후 반환되는 것을 확인할 수 있다.
Counter 객체의 각 key, value를 사용하기 위해서는
Counter 객체를 변환하여 사용하면 된다.
first = Counter([1,2,3,4,1])
print(first.keys())
# dict_keys([1, 2, 3, 4, 1])
first_keys = first.keys()
for key in first_keys:
print(key)
print(f'{first[key]}개')
#1
#2개
#2
#1개
#3
#1개
#4
#1개
collections를 이용하면 이처럼 간편하게 list나 object의 구성 요소들을 중복 여부 판별을 할 수 있게 된다.
다양한 방법으로 활용할 수 있으면 좋을 것 같다.
Pytest - python test framework (0) | 2020.08.13 |
---|---|
AWS EC2에 pyenv로 python 설치하기 (0) | 2020.07.01 |
Django - intro (0) | 2019.07.23 |
dictionary + iteration 딕셔너리와 반복문 (0) | 2019.07.22 |
PIP와 Virtualenv (0) | 2019.07.22 |
댓글 영역