Algorithm/프로그래머스

[프로그래머스/Python] 베스트앨범 - Level3

poppy 2021. 5. 5. 00:49
반응형

programmers.co.kr/learn/courses/30/lessons/42579

 

코딩테스트 연습 - 베스트앨범

스트리밍 사이트에서 장르 별로 가장 많이 재생된 노래를 두 개씩 모아 베스트 앨범을 출시하려 합니다. 노래는 고유 번호로 구분하며, 노래를 수록하는 기준은 다음과 같습니다. 속한 노래가

programmers.co.kr

 

from collections import defaultdict

def solution(genres, plays):
    answer = []
    genre_count = defaultdict(lambda: 0) # 장르별 전체 재생 횟수가 저장된 딕셔너리
    music = defaultdict(lambda: []) # 장르별 각 곡의 고유 번호와 재생 횟수가 저장된 딕셔너리
    
    # 위에 선언된 두 딕셔너리에 값 저장
    i = 0
    for genre, play in zip(genres, plays):
        genre_count[genre] += play
        music[genre].append((i, play))
        i += 1
    
    # genre_count를 재생 횟수(value) 기준 내림차순 정렬
    genre_count = sorted(genre_count.items(), key = lambda x: x[1], reverse = True)
    
    # 베스트앨범에 들어갈 노래의 고유번호 계산
    for g in genre_count:
        # music의 value(곡의 고유번호와 재생 횟수가 튜플로 저장된 배열)를 내림차순 정렬
        sorted_g = sorted(music[g[0]], key = lambda x: x[1], reverse = True)
        
        # 첫번째 곡의 고유번호 배열에 추가
        answer.append(sorted_g[0][0])
        
        # 두 곡 이상일 경우 두번째 곡의 고유번호 배열에 추가
        if len(sorted_g) > 1:
            answer.append(sorted_g[1][0])
            
    return answer

어떻게 구하면 좋을지 방법은 생각나는데 코드로 어떻게 구현해야할지 어려워서 다른 사람들의 코드를 보면서 이해한 뒤 가장 이해하기 쉬운 방식으로 코드를 짰습니다.

 

먼저 두 개의 딕셔너리를 선언합니다. genre_count는 장르별로 전체 재생 횟수가 저장된 딕셔너리이고, music은 장르별로 각 곡의 고유번호와 재생횟수가 저장된 튜플들의 배열이 저장된 딕셔너리입니다. 여기서 장르가 키가 되고, 튜플들의 배열이 값이 됩니다. 값은 다음과 같이 저장되게 됩니다.

 

genre_count {'classic': 1450, 'pop': 3100}
music {'classic': [(0, 500), (2, 150), (3, 800)], 'pop': [(1, 600), (4, 2500)]}

 

 

그 다음 for문을 돌면서 두 딕셔너리에 값을 저장합니다. defaultdict를 사용했기 때문에 딕셔너리에 키의 값이 없으면 기본 값이 저장되게 됩니다. 전체 재생 횟수가 많은 장르순으로 정렬해야하기 때문에 genre_count를 재생 횟수(value) 기준으로 내림차순으로 정렬해줍니다. 

 

장르의 개수만큼 for문을 돌면서 베스트앨범에 들어갈 노래의 고유번호를 answer에 저장합니다. 먼저 전체 재생 횟수가 많은 장르부터 곡을 정렬해줍니다. g는 {'classic' : 1450} 이기 때문에 g[0]은 'classic' 이 됩니다. 그리고 music[g[0]] = music['classic'] = [(0, 500), (2, 150), (3, 800)] 가 됩니다. 따라서 sorted_g 에는 곡의 고유번호와 재생 횟수가 튜플로 저장된 배열을 곡의 재생 횟수 기준 내림차순으로 정렬한 배열이 저장됩니다. 장르에 속한 곡이 무조건 한 곡이상이므로 먼저 첫번재 곡의 고유번호를 answer에 추가합니다. 그 다음 해당 장르에 속한 곡이 두 곡 이상일 경우 두번째 곡의 고유번호를 answer에 추가해줍니다. g[0] 은 (0,500) 이니까 g[0][0]은 0 입니다. 

 

마지막으로 베스트앨범에 들어갈 곡의 고유번호가 저장된 배열을 리턴해줍니다.

 

- 배운 점 -

① defualtdict

그 동안 딕셔너리에 값을 넣을 때 키가 있는지 없는지 검사한 후 있는 경우와 없는 경우를 나누어서 코드를 짰었는데 파이썬 내장 모듈을 쓰면 그렇게 코드를 짜지 않아도 되는 것을 알았다. 파이썬 내장 모듈인 collections의 defaultdict 클래스를 사용하여 기본값을 넣어줄 수 있다. defaultdict 클래스의 생성자로 기본값을 생성해주는 함수를 넣어주면 키의 값이 없는 경우 자동으로 생성자를 통해 넘어온 기본값으로 키의 값을 저장한다.

from collections import defaultdict

dict = defaultdict(int) # defaultdict(lambda: 0) 와 같은 의미
dict[key] += temp

 

② lambda 표현식

lambda는 이름이 없는 익명의 함수이다. lambda 인자 : 리턴 값의 형태로 쓸 수 있다.

sorted() 함수에서 다음과 같이 lambda를 쓸 수 있다.

a = [(1, 2), (5, 1), (0, 1), (5, 2), (3, 0)]

# 인자 없이 sorted()만 쓰면, 리스트 아이템의 각 요소 순서대로 정렬된다.

b = sorted(a)
# b = [(0, 1), (1, 2), (3, 0), (5, 1), (5, 2)]

# key 인자에 함수를 넘겨주면 해당 함수의 반환값을 비교하여 순서대로 정렬한다.
# 키를 기준으로 정렬
c = sorted(a, key = lambda x : x[0])
# c = [(0, 1), (1, 2), (3, 0), (5, 1), (5, 2)]

# 값을 기준으로 정렬
d = sorted(a, key = lambda x : x[1])
# d = [(3, 0), (5, 1), (0, 1), (1, 2), (5, 2)]
반응형