[프로그래머스] 42579

do_large·2022년 9월 17일
0

알고리즘

목록 보기
50/50

문제보기

우선 내가 작성한 코드를 보면 아래와 같다.

function generateMapData (genres, plays) {
   const result = genres.reduce((acc, cur, index)=>{
     	const item = {index, count:plays[index]};
        if(acc[cur]){
            acc[cur].push(item)
        }else{
            acc[cur] = [item]
        }
        return acc;
    },{})
   
    return result;
}


function generateDescListByPlayCount(genres, plays) {
    const result = genres.reduce((acc, cur, index)=>{
        if(typeof acc[cur] === "number"){
            acc[cur] += plays[index];
        }else{
            acc[cur] = plays[index];
        }
        return acc;
    },{})
         
    return Object.keys(result).sort((prev, next) => 
                                    result[next] - result[prev]);
}

function solution(genres, plays) {
    const data = generateMapData(genres, plays);
    const descList = generateDescListByPlayCount(genres, plays);
    
    var answer = [];
    descList.forEach((genre)=> {
        const plate = [...data[genre]];
        plate.sort((prev, next)=> 
            next.count - prev.count || prev.index - next.index
        )

        answer.push(...plate.splice(0, 2).map(({index})=>index));
    })
    
    return answer;
}

고민 과정

우선, 입출력 데이터의 형태는 아래와 같다.
genres와 plays가 일차원으로 나열되어서 넘어오기때문에, 내가 사용하기 편한 방식의 자료구조로 변경하려고 했다.


genre와 play는 index로 짝지어져있음

우선 도출하고싶은 형태는

type Item = {index:number, count:number}

type MappedData = Record<Genre, Item[]>
/**
MappedData 예시
{
	'classic' : [{index: 0, count: 500}, {index: 2, count: 150}, {index:3, count: 800}],
	'pop' : [{index: 1, count: 600}, {index: 4, count: 2500}],
}
*/

이다.

아래는 내가 위에서 작성한 mapped data를 뽑아내기위한 코드인데 2개의 배열을 원하는 형태의 객체로 만들고자 Array.reduce를 사용했다.

function generateMapData (genres, plays) {
   const result = genres.reduce((acc, cur, index)=>{
     	const item = {index, count:plays[index]};
        if(acc[cur]){
            acc[cur].push(item)
        }else{
            acc[cur] = [item]
        }
        return acc;
    },{})
   
    return result;
}

그리고 출력값의 조건을 보면 아래와 같은데,

일단 노래가 많이 재생된 장르의 내림차순 리스트를 뽑아내고자 했다.


function generateDescListByPlayCount(genres, plays) {
    const result = genres.reduce((acc, cur, index)=>{
        if(typeof acc[cur] === "number"){
            acc[cur] += plays[index];
        }else{
            acc[cur] = plays[index];
        }
        return acc;
    },{})
         
    return Object.keys(result).sort((prev, next) => 
                                    result[next] - result[prev]);
}

여기서도 reduce를 썼다.

위에있는 2개의 함수에서 리스트를 한번씩 순회하도록 짰는데,
굳이 저 작업을 구분해서 할 필요가있을까싶다.
자료구조에 좀더 많은 정보가 담겨있으면 reduce를 2번쓰지 않아도 되는걸깝,,?
(이건 개선해야할점임!)

그리고 마지막 함수를 보면
generateMapDatagenerateDescListByPlayCount를 통해 생성한 데이터를 가지고, 출력값의 2,3번째 조건을 맞출 수 있도록 sort를 사용했다.

function solution(genres, plays) {
    const data = generateMapData(genres, plays);
    const descList = generateDescListByPlayCount(genres, plays);
    
    var answer = [];
    descList.forEach((genre)=> {
        const plate = [...data[genre]];
        plate.sort((prev, next)=> 
            next.count - prev.count || prev.index - next.index
        )

        answer.push(...plate.splice(0, 2).map(({index})=>index));
    })
    
    return answer;
}

첨엔 요구사항이 길어보여서 어려울것같았는데 생각보다 어렵지는 않았다.
그런데 문제를 풀기 시작하기전에, 요구사항을 먼저 정리하고, 어떤 데이터 형식을 사용할 지 생각하는 시간을 좀 더 가져야할것같다!

오랜만에 알고리즘 문제 풀었는데, 생각보다 잼썼땅

0개의 댓글