문제 조건에 '많이 재생된 장르의 순서'대로 값을 출력하라는 말이 있기 때문에, 전체 재생 횟수를 관리해야 한다고 생각했다.
입력값에는 아래와 같은 정보가 들어있다.
genres
)["classic", "pop", "classic", "classic", "pop"]
plays
)[500, 600, 150, 800, 2500]
genreToPlayCount
Map 자료구조를 만들어 장르의 전체 재생 횟수를 관리할 수 있다.
입력값이 배열이므로, 전체를 순회하여 genreToPlayCount
의 값을 채워넣을 수 있다.
장르별로 어떤 노래를 가지고있는지 저장할 필요가 있다고 생각했다.
정보를 알고싶은 장르가 선택되고나면, 해당 장르의 노래 정보를 바로 가져다가 조작하는게 합리적이라고 생각했기 때문이다.
따라서, genreToSongList
Map 자료구조를 만들었고 1번과 마찬가지로 전체 배열을 순회해 데이터를 저장해두었다.
여기까지 작업 코드는 아래와 같다.
const genreToPlayCount = new Map();
const genreToSongList = new Map();
for(let i = 0; i < genres.length; i++) {
const [genre, playCount] = [genres[i], plays[i]];
const prevPlayCount = genreToPlayCount.get(genre) || 0;
genreToPlayCount.set(genre, prevPlayCount + playCount);
const prevSongList = genreToSongList.get(genre) || [];
genreToSongList.set(genre, prevSongList.concat({ play: playCount, idx: i }));
}
문제에서는 노래의 id를 배열의 idx로 관리하는데, 위의 Map을 만드는 과정에서 idx가 모두 깨져버리므로 genreToSongList의 노래정보에 idx도 추가해주었다.
문제에 아래와 같은 조건이 있다.
모든 장르는 재생된 횟수가 다릅니다.
이 말을 곱씹어 생각해보니, 굳이 key값을 장르로하는 Map을 만들 필요가 없어보였다. 그리고 아래와 같은 플로우를 생각할 수 있었다.
genreToSongList
에서 노래 정보를 꺼내와 추가 작업을 진행한다.이를 위해 아래와 같은 totalCountToGenre
Map을 만들었다.
const totalCountToGenre = new Map();
genreToPlayCount.forEach((totalCount, genre) => {
totalCountToGenre.set(totalCount, genre);
})
(근데 사실 조금 마음에 안들기는 했다. 그 이유는 아래 생각이나 느낀점에 적어두었다.)
이제 출력을 준비해야한다.
가장 재생 횟수가 많은 장르 순으로 정렬을 해야한다.
Array.from(genreToPlayCount.values())
.sort((a, b) => b - a) // 장르의 재생 횟수가 가장 많은 것부터 내림차순 정렬
위의 코드를 통해 가장 많이 들은 장르의 재생 횟수
는 알 수 있지만, 어떤 장르인지는 알 수 없다.
const genre = totalCountToGenre.get(playCount); // playCount : 위의 배열의 원소 중 하나
그래서 3번 과정에서 이를 매핑해주는 Map을 만들었다. 이제 장르를 알 수 있다.
장르별로 어떤 노래를 가지고 있는지는 2번에서 만든 genreToSongList
Map을 통해 얻어올 수 있다.
해당 노래 리스트에서는 아래와 같은 조건대로 정렬을 수행해야한다.
이는 자바스크립트의 Array.prototype.sort()
함수를 이용해 해결할 수 있다.
4번 ~ 5번 과정을 정리한 코드는 아래와 같다.
Array.from(genreToPlayCount.values())
.sort((a, b) => b - a)
.reduce((ans, playCount) => {
const genre = totalCountToGenre.get(playCount);
const songList = genreToSongList.get(genre);
const sortedSongList = songList
.sort((a, b) => a.play === b.play ? a.idx - b.idx : b.play - a.play)
.slice(0, 2);
ans.push(...(sortedSongList.map(item => item.idx)));
return ans;
}, []);
const solution = (genres, plays) => {
const genreToPlayCount = new Map();
const genreToSongList = new Map();
for(let i = 0; i < genres.length; i++) {
const [genre, playCount] = [genres[i], plays[i]];
const prevPlayCount = genreToPlayCount.get(genre) || 0;
genreToPlayCount.set(genre, prevPlayCount + playCount);
const prevSongList = genreToSongList.get(genre) || [];
genreToSongList.set(genre, prevSongList.concat({ play: playCount, idx: i }));
}
const totalCountToGenre = new Map();
genreToPlayCount.forEach((totalCount, genre) => {
totalCountToGenre.set(totalCount, genre);
})
return Array.from(genreToPlayCount.values())
.sort((a, b) => b - a)
.reduce((ans, playCount) => {
const genre = totalCountToGenre.get(playCount);
const songList = genreToSongList.get(genre);
const sortedSongList = songList
.sort((a, b) => a.play === b.play ? a.idx - b.idx : b.play - a.play)
.slice(0, 2);
ans.push(...(sortedSongList.map(item => item.idx)));
return ans;
}, []);
};
장르
도 전체 재생횟수 많은 순으로 상위 2개만 선택하는 것인줄 알고 넘 복잡하게 생각해서 시간 날렸다.totalCountToGenre
맵 객체를 만들었는데, genreToPlayCount
에 값을 모두 넣은 뒤 key-value 값만 바꾸는 느낌이라.. 굳이 Map을 각각 만들어야하나? 하는 생각이 들었다. 지금 생각해보니 안만들고 기존꺼(genreToPlayCount에) 쓰면 될 것 같은데 한 번 작업해봐야겠다.genreToPlayCount
, genreToSongList
요것도 같은 key값으로 value만 다르게 관리되고 있는데 하나로 합칠수도 있을 것 같다.