아... 이 문제... 실패했다...ㅎ
미련 없이 해답을 보기로..!
👇🏻 문제
https://programmers.co.kr/learn/courses/30/lessons/42579
정답 코드
def solution(genres, plays):
answer = []
d = {e:[] for e in set(genres)}
for e in zip(genres, plays, range(len(plays))):
d[e[0]].append([e[1] , e[2]])
genreSort =sorted(list(d.keys()), key= lambda x: sum(map(lambda y: y[0], d[x])), reverse = True)
for g in genreSort:
temp = [e[1] for e in sorted(d[g],key= lambda x: (x[0], -x[1]), reverse = True)]
answer += temp[:min(len(temp),2)]
return answer
이런 코드는 어떻게 짜는 겁니까 정말. 내 코드는 47줄인데...
한 줄 한 줄 살펴보자...
# 입력 값
genres=["classic", "pop", "classic", "classic", "pop"]
plays=[500,600,150,800,2500]
1. 해시(딕셔너리) 선언하기 d = {'pop': [], 'classic': []}
d = {e:[] for e in set(genres)}
# 내 코드
d = {}
for i in range(len(genres)):
if genres[i] not in play_list:
play_list[genres[i]]=[]
[배울점 1] 위와 아래 놀랍게도 같은 코드...다음부터는 위의 방식으로 쓰도록 하자...(이 바보 멍충아...)
2. 딕셔너리에 값 넣기 d = {'pop': [[600, 1], [2500, 4]], 'classic': [[500, 0], [150, 2], [800, 3]]}
for e in zip(genres, plays, range(len(plays))):
d[e[0]].append([e[1] , e[2]])
genres, plays, len(plays)의 길이가 같으니깐, zip 함수를 이용했다.
아마 나였으면 또 아래와 같이 썼겠지...
# 나였으면 - ㄴㅇㄱ
for genre, play, id in zip(genres, plays, range(len(plays))):
d[genre].append([play , id])
[배울점 2] 변수명 보다는 배열로 쓰는게 더 깔끔하군...물론 내 것이 가독성은 좋지만 (미련)
3. 더 많이 재생된 장르 찾기 genreSort = ['pop', 'classic']
genreSort =sorted(list(d.keys()), key= lambda x: sum(map(lambda y: y[0], d[x])), reverse = True)
이 코드는 배울 수 없다. 과연 내 머리로..?
일단, d의 key들을 배열로 받아 내림차순으로(큰 것 부터) 정렬한다. 문제는 정렬할 키를 어떻게 뽑느냐 이다.
key= lambda x: sum(map(lambda y: y[0], d[x]))
map에 사용할 함수가 일회용이고 길이가 짧기 때문에 임시함수 lambda를 사용하는 것이 효율적이다.
난 lambda에 익숙하지 않아서 저 함수를 일일히 다 작성해보았다.
def play_count(y):
return y[0]
def sum_play_count(x):
return sum(map(play_count, d[x]))
key = sum_play_count
d[x] 는 d.keys()의 집합이다.
map 함수에서 d[x] 에 있는 값들 중 첫번째 요소(y[0] === d[x][0], play_count)를 순회하며 더해준 값(sum)이 정렬 key가 된다.
참고로, 나는 반복문으로 일일히 더했다.ㅋ.
d = {'pop': [[600, 1], [2500, 4]], 'classic': [[500, 0], [150, 2], [800, 3]]}
예시) x = 'pop'일 경우
d['pop'] = [[600,1],[2500,4]]
y = [600,1] , [2500,4]
y[0] = 600, 2500
key 값
'pop' : 600+2500
'classic : 500+150+800
4. 내림차순으로 정렬된 genreSort를 순회하며 가장 많이 재생된 2곡을 answer에 추가해준다.
만약, 재생 수가 같다면 아이디가 더 먼저인 것을 추가해준다. answer = [4, 1, 3, 0]
for g in genreSort:
temp = [e[1] for e in sorted(d[g],key= lambda x: (x[0], -x[1]), reverse = True)]
answer += temp[:min(len(temp),2)]
여기서 또 나와버린 lambda...
temp = [e[1] for e in sorted(d[g],key= lambda x: (x[0], -x[1]), reverse = True)]
이것도 정말 천재같은 코드 🧞♂️ 미쳤다 정말 너무 멋있어
나는 이것을 이해하기 위해 또 엉켜버린 실타래를 풀렀다. (예시는 'pop'으로)
new_array = sorted(d['pop'], key=lambda x:(x[0],x[-1]), reverse=True)
print(new_array)
# 출력 [[2500, 4], [600, 1]]
for e in new_array:
print(e[1])
# 출력 4
# 출력 1
이게 뭐냐면, d['pop']을 조건에 맞게 정렬해 주는 것이다. 조건은 2가지다.
1. 많이 재생된 노래 : x[0] (첫번째 정렬 키)
2. 만약 재생 수가 같다면 번호가 빠른 것 : x[-1] (두번째 정렬 키)
이 두번째 정렬 키는 예를 들어
[[500, 8], [500, 4], [500, 2]] 이렇게 있을 경우, x[0] 이 500으로 같고 번호가 빠른게 먼저 출력되어야 하기 때문에
[[500, 2], [500, 4], [500, 8]] 이렇게 정렬해야만 한다.
하지만, 우리는 x[0] 을 기준으로 이미 내림차순을 하고 있기 때문에 x[1] 을 기준으로 정렬하면
[[500, 8], [500, 4], [500, 2]] 이렇게 된다.
따라서 이를 해결하기 위한 방법이 x[1]이 아니라 -x[1](음수)으로 내림차순하면 x[1]의 오름차순과 같게 된다.
배열을 변형시키지 않는 sorted()를 사용하고 있기에 정렬키를 음수로 생각해 정렬하면 짠 이렇게 된다.
이렇게 정렬한 배열의 1번째 원소 [[2500, 4], [600, 1]] 의 배열이 temp가 된다. temp = [4,1]
for g in genreSort:
temp = [e[1] for e in sorted(d[g],key= lambda x: (x[0], -x[1]), reverse = True)]
# temp = [4,1]
answer += temp[:min(len(temp),2)]
여기에 문제에서 요구하는 또 하나의 조건을 충족시켜 주어야 한다.
장르에 속한 곡이 하나라면, 하나의 곡만 선택합니다. (그렇지 않으면, 2개 선택)
이것을 충족시키기 위해 len(temp)와 2 중 작은 값을 찾아 곡이 하나이면 temp[:1],
두 곡 이상이면 temp[:2] 를 answer에 더해주면 된다.
하하...이 문제 이해하는데 2시간 걸렸다. 1주일 후에 다시 풀어보겠다.
'Python > 문제풀이' 카테고리의 다른 글
[➕ 오답노트] 백준 11478번 (0) | 2022.05.19 |
---|---|
[ ➕ 오답노트] 백준 17298번 오큰수 (0) | 2022.05.17 |
[2021 KAKAO 블라인드 채용] 메뉴 리뉴얼 (0) | 2022.05.10 |
[2] 백준 13458번: 시험감독 (0) | 2022.04.27 |
[1] 백준 12100번: 2048 (Easy) (0) | 2022.04.26 |