상세 컨텐츠

본문 제목

[python] collections.Counter를 사용하여 중복 체크하기

Programming/Python

by 쌩우 2021. 1. 16. 01:34

본문

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의 사용은 아래의 원리와 같이 작동한다.

Collections

Counter - 숫자를 세고 객체로 만들어주기

어떤 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의 구성 요소들을 중복 여부 판별을 할 수 있게 된다.

다양한 방법으로 활용할 수 있으면 좋을 것 같다.

'Programming > Python' 카테고리의 다른 글

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

관련글 더보기

댓글 영역