파이썬/프로그래머스 코딩테스트

[3단계] hash, 베스트앨범

Bentist 2022. 3. 3. 17:00

출처: 프로그래머스 코딩테스트 연습

1. 속한 노래가 많이 재생된 장르를 먼저 수록

{장르: 장르에 속한 노래들의 총 재생 횟수}를 만든다. 추후 value를 기준으로 장르를 정리할 것이다.

2. 장르 내에서 많이 재생된 노래를 먼저 수록

장르 내에 속하므로 전체는 장르로 구분하며, 노래는 고유 번호로 구분하고자 {장르: [고유번호, 재생 횟수]}로 생성한다. 장르와 노래는 1:N 관계이므로 리스트 형태로 값을 추가하겠다.

sum_genres = collections.defaultdict(int) 
dic_total = collections.defaultdict(list)

for genre, value in zip(genres, enumerate(plays)):
    sum_genres[genre] += value[1]
    dic_total[genre].append(value)

 

3. 2번에 의해 [ [0, 800], [2, 800], [1, 300] ] 재생 횟수로 1차 정렬이 완료되었다고 가정하면 고유 번호가 낮은 노래를 먼저 수록해야 한다. 그러나 고유번호는 0부터 자동으로 부여된 인덱스이므로 1차 정렬이 완료되었을 때 이미 낮은 번호로 정렬되어 나온다. 따라서 3번 조건에 의한 추가적인 코드는 필요하지 않다.

만약 고유 번호가 높은 노래를 먼저 수록해야 한다면 sorted() 함수에서 두번째 우선 순위를 부여하면 된다.

a = [(1, 800), (3, 800), (0, 500)]

print(sorted(a, key=lambda x: x[1], reverse=True))
print(sorted(a, key=lambda x: (x[1], x[0]), reverse=True))

>> 
[(1, 800), (3, 800), (0, 500)]
[(3, 800), (1, 800), (0, 500)]

 

sorted(iterable객체, key 매개변수, 옵션(reverse=True))

words = ['aza', 'bbb']

# 오름차순 정렬 
print(sorted(words)) 
>> ['aza', 'bbb']

# 내림차순 정렬 
print(sorted(words, reverse = True)) 
>> ['bbb', 'aza']

# 두 번째 글자(1번 원소) 기준으로 정렬 
print(sorted(words, key=lambda x: x[1])) 
>> ['bbb', 'aza']

 

# 주의사항

5개의 노래가 있는데 예시의 return 값을 보면 4개이다. 문제 설명 최상단에 장르 별로 가장 많이 재생된 노래를 두 개씩 모아 앨범을 출시하려 한다고 문제 설명했으므로 유의하자.

 

최종 문제 풀이

import collections

def solution(genres, plays):
    
    answer = []
    
    dic_total = collections.defaultdict(list)
    sum_genres = collections.defaultdict(int) 

    # enumerate() 함수로 인덱스(고유번호로 사용) 포함한 객체 반환 
    # 장르별 총 재생 횟수 계산 (value[1] = plays 리스트의 값)
    # 장르별 value(인덱스, 재생 횟수) 추가
    for genre, value in zip(genres, enumerate(plays)):
        sum_genres[genre] += value[1]
        dic_total[genre].append(value)     
    
    # sum_genres = {'classic': 2100, 'pop': 3100})에서 value 기준으로 내림차순 적용
    first_choice = sorted(sum_genres.items(), key=lambda x: x[1], reverse=True)  

    for key, val in first_choice:
    	# 가장 많이 재생된 장르가 key로 들어오면, 해당 장르의 (인덱스[0], 재생횟수[1])를 재생횟수 기준 정렬
        second_choice = sorted(dic_total[key], key=lambda x: x[1], reverse=True)
        
        # 장르별 최대 두 개씩만 반환해야 하는 조건 수행 
        for i, v in second_choice[:2]:
            answer.append(i)
    
    return answer

 

# 실수

딕셔너리 a의 value를 기준으로 내림차순 정렬을 할 때, sorted(a, ~ x: x[1])로 작성하여 올바른 결과값이 나온 것으로 착각했다. a.items()없이 a만 호출하면 키 값만 반환하기 때문에 x[1]은 'aa'의 두번째 인덱스 a가 된다. 우연히 'c'의 value 값이 가장 큰 수 였기에 정상적으로 동작하는 것처럼 보였던 것.

a = {'aa': 2000, 'bb': 3000, 'cc':5000}
sorted(a, key=lambda x: x[1], reverse=True)

>> 
['cc', 'bb', 'aa']
---------------------------------------------------
sorted(a.items(), key=lambda x: x[1], reverse=True)