프로그래머스 - 위클리 챌린지 6주차 : 복서 정렬하기

2 minute read

문제는 여기

  1. 전체 승률이 높은 복서의 번호가 앞쪽으로 갑니다. 아직 다른 복서랑 붙어본 적이 없는 복서의 승률은 0%로 취급합니다.
  2. 승률이 동일한 복서의 번호들 중에서는 자신보다 몸무게가 무거운 복서를 이긴 횟수가 많은 복서의 번호가 앞쪽으로 갑니다.
  3. 자신보다 무거운 복서를 이긴 횟수까지 동일한 복서의 번호들 중에서는 자기 몸무게가 무거운 복서의 번호가 앞쪽으로 갑니다.
  4. 자기 몸무게까지 동일한 복서의 번호들 중에서는 작은 번호가 앞쪽으로 갑니다.

※ 승부를 하지 않은 경우 승률계산에서 제외되어야한다. ‘NNWN’ 이면 승률 100%

솔루션

function solution(weights, head2head) {
  
  const compare = (b1, b2) => 
    b1.winRate != b2.winRate ? b2.winRate - b1.winRate
    : b1.expensiveWin != b2.expensiveWin ? b2.expensiveWin - b1.expensiveWin
    : b1.weight != b2.weight ? b2.weight - b1.weight
    : b1.index - b2.index
  ; 
  
  const boxer = head2head.map((v, me) => {
    let winCnt = 0;
    let expensiveWinCnt = 0;
    let vsCnt = v.length;
    const arr = v.split('');
    arr.forEach((element, other) => {
      if(element == 'N') vsCnt--;
      if(element == 'W') {
        winCnt++;
        if(weights[me] < weights[other]) expensiveWinCnt++;
      }
    })

    return {
      'index' : me,
      'weight' : weights[me],
      'winRate': vsCnt == 0 ? 0 : winCnt/vsCnt,
      'expensiveWin': expensiveWinCnt
    }
  });

  return boxer.sort(compare).map(v => v.index+1);
}

const t1 = solution([50,82,75,120],["NLWL","WNLL","LWNW","WWLN"]);
const t2 = solution([145,92,86],["NLW","WNL","LWN"]);
const t3 = solution([60,70,60],["NNN","NNN","NNN"]);

console.log(` t1 : ${t1}, answer : [3,4,1,2]`);
console.log(` t2 : ${t2}, answer : [2,3,1]`);
console.log(` t3 : ${t3}, answer : [2,1,3]`);


Logical OR 연산자를 이용한 Compare 만들기

const compare = (b1, b2) => 
  b1.winRate != b2.winRate ? b2.winRate - b1.winRate
  : b1.expensiveWin != b2.expensiveWin ? b2.expensiveWin - b1.expensiveWin
  : b1.weight != b2.weight ? b2.weight - b1.weight
  : b1.index - b2.index
; 

if/else if 보다 타이핑량이 적어서 선호하는 다중 삼항 연산자를 이용해서 compare 함수를 만들어서 문제를 풀었다.

다른 사람 풀이를 구경하다가 논리연산자로 이걸 구현한 사람들 발견하고 당황했다.

이게 어떻게 가능한지 찾아봤더니,

210907233626.png

그러나 &&와 || 연산자는 사실 두 피연산자 중 하나를 반환하는 것으로, 만약 둘 중 하나가 불리언 값이 아니라면 논리 연산자의 반환 값도 불리언 값이 아닐 수 있습니다.

?! 논리연산자는 언제나 피연산자도, 결과도 boolean 일 거라고만 생각하고 살았다…

false로 변환할 수 있는 표현식은 평가 결과가 null, 0, NaN, 빈 문자열(“”), undefined인 경우입니다.

false로 변환되지 않는 나머지 표현식은 모두 true라는 뜻으로 해석되는 것 같다. 왜냐면 MDN 페이지 예제에서 아래와 같은 경우에 ‘Cat’을 반환하기 때문이다.

var o5 = "Cat" || "Dog";    // t || t returns Cat

그래서 아래와 같은 방법으로 위와 compare 함수를 똑같이 만들 수 있다. 타이핑량도 더 적고 가독성도 더 좋아보인다.

const compare = (b1, b2) => b2.winRate - b1.winRate
  || b2.expensiveWin - b1.expensiveWin
  || b2.weight - b1.weight
  || b1.index - b2.index
; 

b1b2의 값이 같다면, 결과는 0이 될 것이고 0false로 변환될 수 있다. 그러면 || 연산자는 다음 피연산자를 검사하고 그 결과를 리턴한다.

b1b2의 값이 다르다면, 결과는 null, 0, NaN, 빈 문자열(""), undefined가 아니므로 true로 취급된다. 그러면 || 연산자는 b1 - b2 의 결과를 리턴한다.

Reference

  • https://programmers.co.kr/learn/courses/30/lessons/85002/solution_groups?language=javascript
  • https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Expressions_and_Operators