[프로그래머스] 베스트앨범 - JavaScript

Chloé·2022년 3월 13일
0
post-thumbnail

베스트앨범 #해시

출처 - 프로그래머스 코딩테스트 고득점 KIT

💡 문제 접근하기

  • 한 번에 여러 정보를 담은 해시맵을 구성하는 것이 까다로운 문제.
  1. 각 장르별로 a) 장르명, b) 수록된 노래 정보 [인덱스, 재생 횟수] 목록, c) 총 재생횟수 세 가지 정보를 담은 해시맵을 생성한다.
    • 각 정보를 key로 분류하고 불러오기 위해 Object를 사용했다.
  2. 총 재생횟수를 기준으로 각 장르를 sort 한다.
  3. 각 장르를 순회하며 각 장르 내에서 i) 재생횟수를 기준으로, ii) 고유번호를 기준으로 sort한다.
  4. 각 장르를 순회하며 각 장르 내에서 첫 두 개의 음악을 answer 배열에 모아 반환한다.

🔥 문제 풀어보기

Map에 Object를 이용하여 담아보기

function solution(genres, plays) {
  let answer = [];

  // STEP 01. 각 장르별로 노래 정보 [인덱스, 재생 횟수] 목록과 총 재생횟수 정보를 모으자!
  let mH = new Map();
  for (let i = 0; i < genres.length; i++) {
    let obj = mH.get(genres[i]) || { musics: [], cnt: 0 };
    obj.musics.push([i, plays[i]]);
    obj.cnt += plays[i];
    mH.set(genres[i], obj);
  }

  // STEP 02. 각 장르별로 재생 횟수를 sort 하자!
  let chart = [];
  for (let [genre, info] of mH) {
    chart.push([genre, info.musics, info.cnt]);
  }
  chart.sort((a, b) => b[2] - a[2]);

  // STEP 03. 각 장르 내에서 노래들을 순서대로 sort 하자!
  for (let genre of chart) {
    genre[1].sort((a, b) => {
      if (a[1] === b[1]) return a[0] - b[0];
      else return b[1] - a[1];
    });
    // sort한 노래를 각 두 개씩 answer에 모으자!
    let idx = 0;
    while (genre[1].length > idx && idx < 2) {
      answer.push(genre[1][idx][0]);
      idx++;
    }
  }

  return answer;
}
  • 이렇게 접근할 경우, Map이 굉장히 깔끔하고 예쁘게 나온다.
{
  'classic' => { musics: [ [ 0, 500 ], [ 2, 150 ], [ 3, 800 ] ], cnt: 1450 },
  'pop' => { musics: [ [ 1, 600 ], [ 4, 2500 ] ], cnt: 3100 }
}
  • 다만, 이렇게 해시 테이블을 Map으로 만들게 된다면,
    • 처음 테이블을 생성하기가 쉽다는 장점이 있으나,
    • sort()를 사용하기 위해 Array로 다시 변환해줘야 한다.

이전에 풀었던 방법

function solution(genres, plays) {
  var answer = [];

  // step 0. 새로운 해시맵 생성하기
  let mH = new Map();

  // step 1. 각 장르별로 노래 분류하기
  for (let i = 0; i < genres.length; i++) {
    if (mH.get(genres[i])) {
      let temp = mH.get(genres[i]);
      mH.set(genres[i], temp.concat([[i, plays[i]]]));
    } else {
      mH.set(genres[i], [[i, plays[i]]]);
    }
  }

  // step 2. 각 장르별로 1) 재생 횟수 순으로 노래 정렬하기 2) 누적 재생횟수 구하기
  let sorted = [];
  for (let [key, value] of mH) {
    value.sort((a, b) => {
      if (a[1] === b[1]) {
        return a[0] - b[0];
      } else return b[1] - a[1];
    });

    sorted.push([
      key,
      value.reduce((acc, cur) => {
        return acc + cur[1];
      }, 0)
    ]);
    sorted.sort((a, b) => b[1] - a[1]);
  }

  for (let [genre, play] of sorted) {
    let temp = mH.get(genre);
    if (temp.length >= 2) {
      answer.push(temp[0][0]);
      answer.push(temp[1][0]);
    } else {
      answer.push(temp[0][0]);
    }
  }

  return answer;
}

🚀 문제에서 배워보기

Map 다루기

  • 처음에는 Map의 value 값에 바로 접근하기 위해 이렇게 코딩해보았으나,
// STEP 01. 해시맵을 이용하여 장르별로 노래를 분류하되, [고유번호: 재생횟수}]의 형태로 저장한다.
let mH = new Map;
for (let i = 0; i < genres.length; i++) {
  mH.set(genres[i], mH.get(genres[i]) ? mH.get(genres[i]).push(i) : [i]);
}
  • mH.get()은 object를 반환하기 때문에 .push() 메소드를 쓸 수 없다는 에러가 뜬다!
    • mH.get()이 반환하는 값을 변수로 한번 더 할당해주고 push() 해야 한다.
      • 왜 이렇게 되는지 궁금한데 공부할 부분으로 백로그에 달아놓을 것!
profile
클로이 데일리 로그

0개의 댓글