조종 다음은 개발

문제 설명


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

  1. 속한 노래가 많이 재생된 장르를 먼저 수록합니다.
  2. 장르 내에서 많이 재생된 노래를 먼저 수록합니다.
  3. 장르 내에서 재생 횟수가 같은 노래 중에서는 고유 번호가 낮은 노래를 먼저 수록합니다.

노래의 장르를 나타내는 문자열 배열 genres와 노래별 재생 횟수를 나타내는 정수 배열 plays가 주어질 때, 베스트 앨범에 들어갈 노래의 고유 번호를 순서대로 return 하도록 solution 함수를 완성하세요.

제한사항

  • genres[i]는 고유번호가 i인 노래의 장르입니다.
  • plays[i]는 고유번호가 i인 노래가 재생된 횟수입니다.
  • genres와 plays의 길이는 같으며, 이는 1 이상 10,000 이하입니다.
  • 장르 종류는 100개 미만입니다.
  • 장르에 속한 곡이 하나라면, 하나의 곡만 선택합니다.
  • 모든 장르는 재생된 횟수가 다릅니다.

입출력 예

genresplaysreturn

["classic", "pop", "classic", "classic", "pop"] [500, 600, 150, 800, 2500] [4, 1, 3, 0]

입출력 예 설명

classic 장르는 1,450회 재생되었으며, classic 노래는 다음과 같습니다.

  • 고유 번호 3: 800회 재생
  • 고유 번호 0: 500회 재생
  • 고유 번호 2: 150회 재생

pop 장르는 3,100회 재생되었으며, pop 노래는 다음과 같습니다.

  • 고유 번호 4: 2,500회 재생
  • 고유 번호 1: 600회 재생

따라서 pop 장르의 [4, 1]번 노래를 먼저, classic 장르의 [3, 0]번 노래를 그다음에 수록합니다.

 

 

출처 :programmers.co.kr/learn/courses/30/lessons/42579

생각의 흐름


 

일단 문제에 인자로 리스트가 두개 주어졌다.

 

genres = ["classic", "pop", "classic", "classic", "pop"]

 

plays = [500, 600, 150, 800, 2500]

 

 

 

같은 장르가 여러번 반복되는 장르 리스트와 플레이리스트 

 

이 두 리스트가 서로 연관이 있기 때문에 두개의 리스트를 묶어주고 같은 장르끼리 하나로 묶어야겠다고 생각했다.

 

그래서 일단 사전 형태로 만들어서 {classic : [500, 150, 800], pop : [..]}

 

이런식으로 만들어 보려고 했다.

 

그리고 값이 큰 순서대로 정렬하고 추가로 

 

사전에 value값(여기선 [500, 150, 800] 등등) 리스트 맨 앞에 value값의 총합을 추가해야겠다고 생각했다.

 

왜냐하면 결국 총합을 알아야 가장 많이 재생된 장르를 알 수 있으니까.. ㅎㅎ

 

def solution(genres, plays):
    dic = {}



    for type , times in zip(genres, plays):
        if type in dic.keys():
            dic[type].append(times)

        else:
            dic[type] = [times]
    for x , y in dic.items():
        dic[x] = sorted(dic[x], reverse=True)
        dic[x].insert(0, sum(dic[x]))

	return dic

(return의 들여쓰기가 잘못되어 있지만 무시 부탁드립니다ㅎㅎ)

 

dic의 값: {'classic': [1450, 800, 500, 150], 'pop': [3100, 2500, 600]}

 

 

 

 

이제 dic value의 첫번째 요소(각 장르의 총합)를 가지고 재생횟수가 높은 장르를 순서대로 정렬하고 그 장르의 재생횟수가 들어있는

list의 1번과 2번 값의 index를 구하면 되는 것이다.(왜냐하면 0번 index는 총합이기 때문이다)

 

하지만 여기서 index를 구할때 dic value의 인덱스를 구하는 것이 아닌 인자로 받은 plays에서의 index를 받아야 정답이 나온다.

 

그리고 또 주의할 점이 장르의 맞는 최대값의 index를 구해야한다.

 

무슨말이냐면 

 

만약 pop의 최대 재생횟수가 700이라고 하고 그냥 plays에서 700의 index를 찾으면 다른 장르이고 재생횟수가 700인 값의 index가

출력될 수 있다.

 

이걸 해결하기 위해서 그냥 재생횟수만을 가지고 갚을 찾을 수는 없고 장르와 재생횟수 두개를 가지고 갚을 찾아야 한다.

 

그래서 나는 앞에 코딩에도 사용을 했지만 설명을 하지 않았던 zip을 이용했다.

 

zip은 간단히 말하면 두 리스트를 하나로 묶어주는 함수이다.

 

예시는 다음과 같다.

genres= ["classic", "pop", "classic", "classic", "jazz", "pop", "Rock", "jazz"]
plays = [500, 600, 150, 800, 1100, 2500, 100, 1000]
test= list(zip(genres, plays))
print(test)
#[('classic', 500), ('pop', 600), ('classic', 150), ('classic', 800), ('jazz', 1100), ('pop', 2500), ('Rock', 100), ('jazz', 1000)]

 

 

 

이제 dic에서 장르이름과 재생횟수를 인자로 가져와서 (장르, 재생횟수)의 index를 찾으면 우리가 원하는 index가 나올 것이다.

 

이렇게 생각하고 코드를 작성했다.

 

 

 

 

top_genres_list = sorted(dic.items(), key=(lambda x : x[1][0]), reverse=True)
top_genres = [a[0] for a in top_genres_list]

zip_list = list(zip(genres, plays))
for i in top_genres:
  a = (i, dic[i][1])
  first_value_index = zip_list.index(a)
  answer.append(first_value_index)
  zip_list[first_value_index] = (0, 0)
try:
  b = (i, dic[i][2])
  second_value_index = zip_list.index(b)
  answer.append(second_value_index)
  zip_list[second_value_index] = (0, 0)
except:
  continue

(맨 처음 썼었던 코드와 이어지는 코드이다.)

 

좀 복잡해 보이지만 설명을 하나씩 해보면

 

lambda를 활용하여 dic의 값 {'classic': [1450, 800, 500, 150], 'pop': [3100, 2500, 600]} 에서 1450와 ,3100 같은 총합의 값을 가지고

정렬을 하여 top_genres_list 라는 변수를 지정했다.

 

top_genres_list는 dic을 재생횟수가 많은 장르 순서대로 정렬한 것이다.

 

top_genres_list의 keys만 list로 저장한 것이 top_genres 라는 변수이고

 

top_genres를 출력하면 다음과 같다.

['pop', 'classic']

 

 

 

 

이제 장르의 이름을 for구문으로 가져오고 (장르, 재생횟수1등) (장르, 재생횟수2등)의 인덱스를 추출해서 리턴하면 된다.

 

그러기 위해서 일단 다시한번 zip으로 genres와 plays를 묶고 리스트로 만들어줬다. 

 

그래야먄 인덱스를 리턴했을 때 정답이기 때문이다.

 

 

 

 

for 구문 으로 dic[장르][1], dic[장르][2]의 인덱스를 추출을 하고 

 

추출한 인덱스를 answer 리스트에 append 하여 return answer 을 하도록 코드를 작성했다.

 

 

 

 

그런데 여기서 고려해야 할 사항이 하나 더 있었다. 

 

만약 한 장르에서 노래가 하나일 경우 dic[장르][2]의 값은 존재하지 않기 때문에 오류가 발생했었다,

 

그래서 try 함수를 사용해서 만약 dic[장르][2]를 추출하는 과정에서 오류가 발생하면 그 값이 없다는 판단을 하고

 

그냥 넘어가도록 했다. for 구문이 끝나고 return answer을 하면 정상적으로 정답이 나오는 것을 확인할 수 있다.

 

 

 

 

 

완성된 코드


def solution(genres, plays):
    # clasic : [총합,50,40]
    dic = {}
    answer = []


    for type , times in zip(genres, plays):
        if type in dic.keys():
            dic[type].append(times)

        else:
            dic[type] = [times]
    for x , y in dic.items():
        dic[x] = sorted(dic[x], reverse=True)
        dic[x].insert(0, sum(dic[x]))

    # dic
    # {'classic': [1450, 800, 500, 150], 'pop': [3100, 2500, 600], 'jazz': [2100, 1100, 1000], 'Rock': [100, 100]}

    # 총합계가 높은 장르 순서대로 ['pop', 'jazz', 'classic', 'Rock']
    top_genres_list = sorted(dic.items(), key=(lambda x : x[1][0]), reverse=True)
    top_genres = [a[0] for a in top_genres_list]

    zip_list = list(zip(genres, plays))
    for i in top_genres:
        a = (i, dic[i][1])
        first_value_index = zip_list.index(a)
        answer.append(first_value_index)
        zip_list[first_value_index] = (0, 0)
        try:
            b = (i, dic[i][2])
            second_value_index = zip_list.index(b)
            answer.append(second_value_index)
            zip_list[second_value_index] = (0, 0)
        except:
            continue

    return answer

 

스스로 피드백


이 문제를 해결하기 위해서 3일 정도의 시간이 걸렸다...

 

물론 3일동안 24시간 고민했던 것은 아니다.

 

시간이 날 때마다 틈틈히 시도 했었다.

 

그래서 새로 시도할 때마다 내가 전에 썼던 코드를 읽어보면서 다시 코드를 이해하는데

 

시간이 좀 소요 되었다. 물론 코드가 짧고 많이 복잡하지 않지만 그래도

 

문제를 풀기 위해선 내가 썼던 코드를 완벽하게 이해해야 더 이어서 쓸 수 있을 것 같았기 때문이다.

 

이 문제를 풀면서 몇 가지 고쳐야 할 점들이 보였다.

 

  • 변수이름을 직관적으로 정하기
  • 중간중간 주석을 넣어서 이해하기 쉽게 하기
  • lambda에 대해서 더 공부하기

변수 이름이 다 비슷비슷 하니까 나중에 봤을 때 저 변수는 정확히 어떤 값들을 가지고 있는지 내가 쓴 코드여도

 

쉽게 알아보지 못했었다...(멍청멍청)

 

그래서 변수명을 설정할 때 직관적으로 알 수 있는 변수명을 쓰도록 노력해야 겠다고 생각했다.

 

 

 

그리고 주석을 중간에 넣지 않으니까 시간이 지나고 다시 코드를 쓰려고 했을 때 내가 지금 어떤 것들을 하고 있었는지에 대한 이해를

 

다시 해야 했었다.. 그래서 중간중간에 주석을 넣어서 이해하는데 시간을 단축시켜야겠다고 생각했다..

 

 

lambda는 며칠전에 알게 되었는데 역시 know와 understand는 다른것 같다.

 

구글링을 통해서 lambda를 대충 보는 것 만으로는 활용할 수 없다고 생각했다.

 

완전히 이해를 하고 나서야 필요한 순간이 올 때 생각이 나서 어떻게 활용해야 할 지 바로 알고 사용할 수 있다고 느꼈다.

 

그래서 lambda를 know 하는 단계를 넘어서 understand를 하는 단계로 나아가게 여러곳에 활용해보는 연습을 해야겠다고 느꼈다.

profile

조종 다음은 개발

@타칸

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!