목표
- 베스트 엘범 문제 풀이
- 문제 링크 : https://programmers.co.kr/learn/courses/30/lessons/42579?language=javascript
문제 요구사항
- 속한 노래가 가장 많이 재생된 장르를 수록합니다.
- 장르 내에서 많이 재생된 노래를 먼저 수록합니다.
- 장르 내에서 재생 횟수가 같은 노래 중에서는 고유 번호가 낮은 노래를 먼저 수록합니다.
문제 풀이
최대한 변수를 많이 선언하지 않는 방향으로 풀이
-
데이터 추상화
genres
,plays
값이 다른 두개의 데이터로 내려온다.
문제를 해결하기 위해서는하나의 데이터
로 묶어 줄 필요가 있다. 또한 장르 내에서 많이 재생된 노래 순으로 수록 하기 때문에장르별 재생 횟수
도 값이 있어야 한다. 마지막으로 장르 내에서 재생횟수를 기준으로 노래를 수록 해야하기 때문에노래별 재생 횟수
값도 가지고 있는 데이터로 추상화 하자.// 모든 노래 데이터 const musics = genres.reduce( ( genresList, val, idx) => { // console.log( genresList, val, idx); if(!genresList[val]){ genresList[val] = { totalPlays : plays[idx], plays : [ [idx, plays[idx] ]]} }else { genresList[val].totalPlays += plays[idx]; genresList[val].plays = [ ...genresList[val].plays, [idx, plays[idx]] ] } return genresList; }, {}) // 장르 크기 정렬된 노래 데이터 const genreOrderedMusics = Object.values(musics).sort( (a, b) => { return b.totalPlays - a.totalPlays; }) console.log( genreOrderedMusics ); => 실행결과 [ { totalPlays: 3100, plays: [ [Array], [Array] ] }, { totalPlays: 1450, plays: [ [Array], [Array], [Array] ] } ]
-
문제 해결
- 장르별 재생횟수가 많은 순서대로 데이터를 만들었으므로
요구사항 1.
은 해결. 요구사항 2.
를 해결하기 위해서는 받은 데이터의plays
의 크기별로 정렬 한다.요구사항 3.
를 해결하기 위해서는 2.번에서 정렬할때 낮은 번호 순으로 정렬되도록 구현 한다.
// 베스트 엘범에 들어갈 고유 번호 구하는 로직 genreOrderedMusics.forEach((genre) => { // 장르 내에서 많이 재생된 노래 순으로 정렬 // 크기 같은 경우는 따로 처리 불필요. 배열이 낮은순으로 있기 때문 genre.plays.sort((a,b) => { return b[1] - a[1]; } ) // 재생 회수 별로 수록. 고유번호가 낮은 경우 어케됨? if(genre.plays.length > 1 ){ answer = [ ...answer, genre.plays[0][0], genre.plays[1][0]]; }else { answer = [ ...answer, genre.plays[0][0] ] } }) console.log(answer)
- 장르별 재생횟수가 많은 순서대로 데이터를 만들었으므로
결론
- 데이터를 가공하는데 reduce, map 이 효율적으로 사용되니 이 두개의 함수의 사용범을 알고 익숙해질 필요가 있다.
- 데이터 추상화가 매우 중요하다. 어떻게 추상화 하느냐에 따라 이후 로직이 복잡해 질수 있기 때문이다.
다른 사람의 기가막힌 풀이..
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;
return a.index - b.index;
})
.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);
}
최초 연습 풀이
- 데이터 추상화
genres
,plays
두개의 다른 배열로 값이 내려온다.
이 두개의 배열을 합쳐 하나의 데이터로 만들어주자
const songs = genres.map( (ele, idx) => {
return { genre : ele , idx : idx, plays : plays[idx] }
});
console.log( songs);
=> 실행 결과
[
{ genre: 'classic', idx: 0, plays: 500 },
{ genre: 'pop', idx: 1, plays: 600 },
{ genre: 'classic', idx: 2, plays: 150 },
{ genre: 'classic', idx: 3, plays: 800 },
{ genre: 'pop', idx: 4, plays: 2500 }
]
장르별 재생 횟수를 알아야 가장 많이 재생된 장르를 먼저 수록할수 있기 때문에 장르별 재생 횟수를 가진 데이터를 만들자.
// 장르 별 재생 횟수 데이터
const genresPlays = genres.reduce((genresList, g, i) => {
if (!genresList[g]) {
genresList[g] = plays[i];
} else {
genresList[g] += plays[i];
}
return genresList;
}, {});
console.log(genresPlays)
=> 실행 결과
{ classic: 1450, pop: 3100 }