베스트 앨범
22123 단어 high order functiondicdic
1. 베스트 앨범
각 장르마다 곡이 들어가 있다. 이때 각 장르별로 가장 재생이 많이 된 상위 2곡을 선정해서 앨범을 만들려고 한다. 예시를 살펴보자
genres plays return
["classic", "pop", "classic", "classic", "pop"] [500, 600, 150, 800, 2500] [4, 1, 3, 0]
우선 제일 많이 재생된 장르 순으로 곡 2개가 담긴다. pop(3,100회 재생 됨) , classic(1,450회 재생 됨) 이므로 pop에서 가장 많이 재생된 곡 2개가 먼저 담긴다.
이때 재생된 횟수가 높은것이 먼저 담긴다.(4,1)
재생횟수가 같다면 고유번호가 적은것이 먼저 담긴다.
장르내에서 재생된 곡이 1개밖에 없다면 그걸 담는다.
2. 접근 방법
두 가지 solution이 있다. 두개다 기가막힌 solution이다.
2-1. 첫번째 solution
- pseudo code
- dic을 만들어서 장르별 총 재생횟수를 저장한다
- genres를 map으로 순회하면서 genre,count(재생횟수),idx(고유번호),를 obj에 담아서 저장한다
- 그 결과를 그대로 이어받아서 sort한다.(genre별, 재생횟수별, 고유번호별로 다중 sort를 할 수 있다)
- 장르가 다르면 dic을 사용해서 genre 별로 sort
- count가 다르면 count 별로 sort
- idx가 다르면 idx 별로 sort
- filter를 통해 상위 랭크 2개만 선정하고 나머진 걸러냄
- dupDic에 genre별로 갯수를 저장
- dupDic에 genre갯수가 2이상이면 false로 걸러냄
- 이제 완성된 obj안에서 map을 통해서 idx만 걸러내면 끝!
function solution1(genres, plays) {
let dic = {};
genres.forEach((t, i) => {
dic[t] = dic[t] ? dic[t] + plays[i] : plays[i];
});
let dupDic = {}; // 장르당 곡이 3개넘어가는게 있는지 판별하기 위함.
return genres
// 장르, 재생수, 고유번호를 각각 담음. sort할때 쓰려고.
.map((t, i) => ({ genre: t, count: play[i], index: i }))
// sort의 다중정렬 가능.
.sort((a, b) => {
// 장르가 다르면 위의 dic을 사용하여 가장 인기있는 장르를 토대로 내림차순정렬
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;
});
// 장르 내에서 상위 랭크 2개만 선정하고 나머지는 false를 통해 걸러짐.
// dupDic 에서 장르의 갯수가 담김.
.filter((t,i)=>{
if(dupDic[t.genre] >=2) return false
dupDic[t.genre] = dupDic[t.genre]?dupDic[t.genre] +1:1
return true
// 최종적으로 정렬되고 걸러진 상태에서 고유번호만 순서대로 추출하면 끝!
}).map(t => t.index)
}
filter전까지의 상황임
0: {genre: "pop", count: 2500, index: 4}
1: {genre: "pop", count: 600, index: 1}
2: {genre: "classic", count: 800, index: 3}
3: {genre: "classic", count: 150, index: 0}
4: {genre: "classic", count: 150, index: 2}
여기서 마지막에 클래식 obj는 필터링되서 없어짐. 장르당 가장 많이 재생된것 2개만 있어야 하므로.
깔끔 그 자체다...
크... 외국어를 유창하게 하는 사람을 보는것 같은 느낌..섹시하다.
깔끔 세련 편함 그냥 기분좋게 하는 요소는 다들어가 있다고 보면 됨.
요걸 계속 적어보면서 연습하자. sort,filter,map 잘 사용했고, obj도 적절히 잘 사용한 것 같다.
2-2. 두 번째 solution
- pseudo code
- songs안에 genre,play,no(고유번호)를 key로 삼고 obj안에 저장해서 자료구조를 만듬
- 장르와 재생된 횟수를 합산해서 genrePlayCnt에 push함
- thisGenre안에 songs의 parameter로 현재 song에 있는 genre만 find해서 담아줌
- thisGenre가 없으면 genre,play를 obj안에 담아서 genrePlayCnt에 push해줌
- 그게 아니면 thisGenre.play에다가 song의 play를 더함.
- 그렇게 장르별로 통틀어서 재생횟수가 구해지면 genrePlayCnt를 내림차순 sort함
- 내림차순된 genrePlayCnt를 forEach를 통해 loop한다.
- thisGenreSongs 에다가 현재 genre와 같은 genre를 songs에서 추출해서 할당한다
- play순으로 내림차순(장르별로는 이미 정렬했으므로, 같은 상태이므로 장르를 정렬할 필요는 없다)
- 그럼 제일 앞에 두개의 고유번호만 answer에 push하면 됨!
function solution2(genre, plays) {
let answer = [];
let songs = genres.map((genre, index) => {
return {
no: index,
genre: genre,
play: plays[index],
};
});
let genrePlayCnt = [];
// 장르와 재생된 횟수를 합산해서 genrePlayCnt에 push함
songs.forEach((song) => {
let thisGenre = genrePlayCnt.find(
(genrePlay) => genrePlay.genre === song.genre
);
if (!thisGenre) {
genrePlayCnt.push({
genre: song.genre,
play: song.play,
});
} else thisGenre.play += song.play;
});
// 장르 통틀어서 재생된 횟수를 내림차순으로 정렬
genrePlayCnt.sort((a, b) => b.play - a.play);
genrePlayCnt.forEach((genrePlay) => {
// genrePlayCnt에서 정렬한 대로 하나씩 loop함
// pop이 먼저이므로 pop에 해당하는 song만 뽑아내서 thisGenreSongs에 저장
let thisGenreSongs = songs.filter((song) => song.genre === genrePlay.genre);
});
// 플레이 순으로 내림차순. 자동으로 고유번호랑 같이 정렬됨
thisGenreSongs.sort((a, b) => b.play - a.play);
// 제일 많이 플레이된곡의 고유번호를 answer에 push
answer.push(thisGenreSongs[0].no);
// 그 다음 2번째 곡이 있으면 2번째 곡의 고유번호를 push함
if (thisGenreSongs.length > 1) {
answer.push(thisGenreSongs[1].no);
}
return answer;
}
- songs안에 genre,play,no(고유번호)를 key로 삼고 obj안에 저장해서 자료구조를 만듬
- 장르와 재생된 횟수를 합산해서 genrePlayCnt에 push함
- thisGenre안에 songs의 parameter로 현재 song에 있는 genre만 find해서 담아줌
- thisGenre가 없으면 genre,play를 obj안에 담아서 genrePlayCnt에 push해줌
- 그게 아니면 thisGenre.play에다가 song의 play를 더함.
- 그렇게 장르별로 통틀어서 재생횟수가 구해지면 genrePlayCnt를 내림차순 sort함
- 내림차순된 genrePlayCnt를 forEach를 통해 loop한다.
- thisGenreSongs 에다가 현재 genre와 같은 genre를 songs에서 추출해서 할당한다
- play순으로 내림차순(장르별로는 이미 정렬했으므로, 같은 상태이므로 장르를 정렬할 필요는 없다)
- 그럼 제일 앞에 두개의 고유번호만 answer에 push하면 됨!
function solution2(genre, plays) {
let answer = [];
let songs = genres.map((genre, index) => {
return {
no: index,
genre: genre,
play: plays[index],
};
});
let genrePlayCnt = [];
// 장르와 재생된 횟수를 합산해서 genrePlayCnt에 push함
songs.forEach((song) => {
let thisGenre = genrePlayCnt.find(
(genrePlay) => genrePlay.genre === song.genre
);
if (!thisGenre) {
genrePlayCnt.push({
genre: song.genre,
play: song.play,
});
} else thisGenre.play += song.play;
});
// 장르 통틀어서 재생된 횟수를 내림차순으로 정렬
genrePlayCnt.sort((a, b) => b.play - a.play);
genrePlayCnt.forEach((genrePlay) => {
// genrePlayCnt에서 정렬한 대로 하나씩 loop함
// pop이 먼저이므로 pop에 해당하는 song만 뽑아내서 thisGenreSongs에 저장
let thisGenreSongs = songs.filter((song) => song.genre === genrePlay.genre);
});
// 플레이 순으로 내림차순. 자동으로 고유번호랑 같이 정렬됨
thisGenreSongs.sort((a, b) => b.play - a.play);
// 제일 많이 플레이된곡의 고유번호를 answer에 push
answer.push(thisGenreSongs[0].no);
// 그 다음 2번째 곡이 있으면 2번째 곡의 고유번호를 push함
if (thisGenreSongs.length > 1) {
answer.push(thisGenreSongs[1].no);
}
return answer;
}
첫 번째 만큼 깔끔한건 아니지만 나름 로직을 잘 정리해서 구현했다.
obj를 이용해서 정보를 잘 정리하고 필요할때마다 뽑아쓰는 기술이 돋보임.
그냥 두개다 너무 친근하고 깔끔한 느낌이다.
진짜 오늘 또 느낀다. 매일 느낀다. 너무 감사하고 신기하고 뿌듯하다...눈물나올것 같다.
Author And Source
이 문제에 관하여(베스트 앨범), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@yhko1992/베스트-앨범저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)