프로그래머스 : 베스트앨범

KHW·2021년 4월 12일
0

알고리즘

목록 보기
17/37

문제

53.3/100


기본적인 내용

genres라는 1차원배열과 plays라는 1차원배열이 존재하며
이때, 각 장르마다의 총합플레이시간이 가장큰 장르를 기준으로 2개씩 뽑아낸다. (1개밖에 없을경우 1개만 가능)


객체의 형태로 장르의 프로퍼티를 가진 총합을 value로 갖는 객체 구현하기

나의 방법

    for(let i=0;i<plays.length;i++)
        {
            if(total[genres[i]] === undefined){
                total[genres[i]] = plays[i];
            }
            else
                total[genres[i]] += plays[i];
            
        }

해당 이름의 장르 프로퍼티가 없다면 plays값을 넣고 그게 아니라면 값을 더해준다.


다른 사람의 방법

    var dic = {};		//이부분 존나중요하니 기억해 설정안하면 에러떠
    genres.forEach((t,i)=> {
        dic[t] = dic[t] ?  dic[t] + plays[i] :plays[i];        
    });

간단한 삼항연산자로 존재한다면 더한값을쓰고 아니라면 처음 plays값을 넣는다.


객체 형태 지정

genres.map((t,i)=> ({genre : t, count:plays[i] , index:i}))

ex) ["classic", "pop", "classic", "classic", "pop"], [500, 600, 150, 800, 2500] 라면 해당 내용은

{ genre: 'classic', count: 500, index: 0 }
{ genre: 'pop', count: 600, index: 1 }
{ genre: 'classic', count: 150, index: 2 }
{ genre: 'classic', count: 800, index: 3 }
{ genre: 'pop', count: 2500, index: 4 }

이러한 형태로 존재

중요한 점 : 리턴되는 {}부분이 ()로 묶여있어야한다.!!!


sort 함수

배열안의 객체에도 적용이 가능하다. (각각의 객체를 하나의 세트로 본다.)

ex)

let saveArray = [
  { genre: 'pop', count: 600, index: 1 },
  { genre: 'pop', count: 2500, index: 4 },
  { genre: 'classic', count: 500, index: 0 },
  { genre: 'classic', count: 150, index: 2 },
  { genre: 'classic', count: 800, index: 3 },
  { genre: 'magic', count: 1000, index: 5 }
];

let dic = 	{ classic: 1450, pop: 3100 ,magic:1000};

console.log(saveArray.sort((a,b)=>a.count -b.count));		//(1)
console.log(saveArray.sort((a,b)=>dic[a.genre] -dic[b.genre]));		//(2)

(1)

count에 따라 오름차순으로 배열이 정렬된다.

[
  { genre: 'classic', count: 150, index: 2 },
  { genre: 'classic', count: 500, index: 0 },
  { genre: 'pop', count: 600, index: 1 },
  { genre: 'classic', count: 800, index: 3 },
  { genre: 'magic', count: 1000, index: 5 },
  { genre: 'pop', count: 2500, index: 4 }
]

(2)

dic배열안의 프로퍼티 값에 따라 오름차순으로 배열이 정렬된다.

[
  { genre: 'magic', count: 1000, index: 5 },
  { genre: 'classic', count: 150, index: 2 },
  { genre: 'classic', count: 500, index: 0 },
  { genre: 'classic', count: 800, index: 3 },
  { genre: 'pop', count: 600, index: 1 },
  { genre: 'pop', count: 2500, index: 4 }
]

정리

따라서 sort 함수는 필요에따라 배열안에 객체형태의 틀에도 적용되어 해당 값을 비교하여 오름차순을 원하면 sort((a,b)=> a.대상 - b.대상) 과 같은 형태로 하고
내림차순을 원하면 sort((a,b) => b.대상 - a.대상) 과 같은 형태를 쓴다.


sort 적용시키기

.sort((a,b)=>{               
               if(a.genre !== b.genre) return dic[b.genre] - dic[a.genre];
               if(a.count !== b.count) return b.count - a.count;
           })

위와같은 형태로 기준은 장르가 가장많이 재생된것을 먼저 기준을 잡고 그 후는 해당 장르에서 count가 가장 많이된 것을 고르게 한다. (내림차순 즉,b - a 형태)


filter 함수

let saveArray = [
  { genre: 'pop', count: 600, index: 1 },
  { genre: 'pop', count: 2500, index: 4 },
  { genre: 'classic', count: 500, index: 0 },
  { genre: 'classic', count: 150, index: 2 },
  { genre: 'classic', count: 800, index: 3 },
  { genre: 'magic', count: 1000, index: 5 }
];

let dic = 	{ classic: 1450, pop: 3100 ,magic:1000};

console.log(saveArray.filter((t)=> {
  if(t.genre == 'pop')
    return false;
  else
    return true;
}))

특정 내용에 따라 true를 리턴하면 정상값을 리턴하고 false를 리턴하면 해당 값을 리턴하지 않는다.

console.log 결과

[
  { genre: 'classic', count: 500, index: 0 },
  { genre: 'classic', count: 150, index: 2 },
  { genre: 'classic', count: 800, index: 3 },
  { genre: 'magic', count: 1000, index: 5 }
]

filter 함수 적용시키기

.filter(t=>  {
               if(dupDic[t.genre] >= 2) return false;
               dupDic[t.genre] = dupDic[t.genre] ? dupDic[t.genre]+ 1 : 1;
               return true;
            })

가져온 배열형태의 객체의 프로퍼티가 없다면 생성하고 1을 추가하고 있다면 해당 프로퍼티 값에 1을 추가하는 형태를 진행하면서 해당 프로퍼티 값이 2보다 크다면 그 후 내용은 return false를 통해 반환하지 않는 역할을 한다.


map 함수 적용시키기

.map(t=> t.index);

해당 배열형태의 객체의 index부분만 가져와 처리한다.


전체코드

function solution(genres, plays) {
    var dic = {};
    genres.forEach((t,i)=> {
        dic[t] = dic[t] ?  dic[t] + plays[i] :plays[i];        
    });

    var dupDic = {};
    return genres          
          .map((t,i)=> ({genre : t, count:plays[i] , index:i}))
          .sort((a,b)=>{               
               if(a.genre !== b.genre) return dic[b.genre] - dic[a.genre];
               if(a.count !== b.count) return b.count - a.count;
           })
           .filter(t=>  {
               if(dupDic[t.genre] >= 2) return false;
               dupDic[t.genre] = dupDic[t.genre] ? dupDic[t.genre]+ 1 : 1;
               return true;
            })
           .map(t=> t.index);    
}

중요부분 : sort나 filter를 배열안의 객체에 적용할수있고 해당 프로퍼티 값에 sort를 적용하여 처리하면 오름차순 혹은 내림차순 처리가 가능하면서 해당 객체가 세트로 전부 적용되는 형태가 된다.


또 다른 정답코드

function solution(genres, plays) {
    const genreMap = new Map();
    genres.map((genre,idx)=>[genre,plays[idx]])
    .map(([genre,play],idx)=>{
        const data = genreMap.get(genre) || {total:0 , songs:[]};
        genreMap.set(genre,{
            total : data.total + play,
            songs : [...data.songs,{play,idx}]
                     .sort((a,b)=>b.play-a.play)
                     .slice(0,2)
        })
    })
    
    return [...genreMap.entries()]
    .sort((a,b)=>b[1].total - a[1].total)
    .flatMap(item => item[1].songs)
    .map(song=>song.idx)
}

분석하기

const genreMap = new Map();
    genres.map((genre,idx)=>[genre,plays[idx]])		
    .map(([genre,play],idx)=>{
        const data = genreMap.get(genre) || {total:0 , songs:[]};	//1.
        genreMap.set(genre,{
            total : data.total + play,		//2.
            songs : [...data.songs,{play,idx}]
                     .sort((a,b)=>b.play-a.play)
                     .slice(0,2)		//3.
        })
    })
  1. 각각의 genre와 play마다 기존에 genreMap에 genre가 없을 경우 {total:0 , songs:[]}로 처리를 진행하고 만약 있을경우 genreMap.get(genre)로 추가하여 처리한다.
  2. total은 기존값에 play를 추가한다.
  3. songs는 기존의 {play, idx}인 data.songs에 새로운 {play, idx}를 추가한 것을 정렬하고 2개만 잘라낸다.
    return [...genreMap.entries()]		//1.
    .sort((a,b)=>b[1].total - a[1].total)	//2.
    .flatMap(item => item[1].songs)		//3.
    .map(song=>song.idx)			//4.
  1. 객체의 경우 sort를 못하므로 {} 형태를 []로 바꿔준다.
  2. 속한 노래가 많이 재생된 장르를 위한 sort를 하고
  3. 분리한 부분의 songs를 참고하고
  4. songs의 idx를 참고해서 리턴한다.
profile
나의 하루를 가능한 기억하고 즐기고 후회하지말자

0개의 댓글