CK 013 | 복서 정렬하기(python)

This Is Empty.·2021년 9월 6일
0

codekata

목록 보기
13/35
post-thumbnail

부제 : ZeroDivisionError 의 늪..

문제

🔗 위클리 챌린지 | 6주차 - 복서 정렬하기

복서 선수들의 몸무게 weights와, 복서 선수들의 전적을 나타내는 head2head가 매개변수로 주어집니다. 복서 선수들의 번호를 다음과 같은 순서로 정렬한 후 return 하도록 solution 함수를 완성해주세요.

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

제한사항

  • weights의 길이는 2 이상 1,000 이하입니다.
    • weights의 모든 값은 45 이상 150 이하의 정수입니다.
    • weights[i] 는 i+1번 복서의 몸무게(kg)를 의미합니다.
  • head2head의 길이는 weights의 길이와 같습니다.
    • head2head의 모든 문자열은 길이가 weights의 길이와 동일하며, 'N', 'W', 'L'로 이루어진 문자열입니다.
    • head2head[i] 는 i+1번 복서의 전적을 의미하며, head2head[i][j]는 i+1번 복서와 j+1번 복서의 매치 결과를 의미합니다.
      • 'N' (None)은 두 복서가 아직 붙어본 적이 없음을 의미합니다.
      • 'W' (Win)는 i+1번 복서가 j+1번 복서를 이겼음을 의미합니다.
      • 'L' (Lose)는 i+1번 복사가 j+1번 복서에게 졌음을 의미합니다.
    • 임의의 i에 대해서 head2head[i][i] 는 항상 'N'입니다. 자기 자신과 싸울 수는 없기 때문입니다.
    • 임의의 i, j에 대해서 head2head[i][j] = 'W' 이면, head2head[j][i] = 'L'입니다.
    • 임의의 i, j에 대해서 head2head[i][j] = 'L' 이면, head2head[j][i] = 'W'입니다.
    • 임의의 i, j에 대해서 head2head[i][j] = 'N' 이면, head2head[j][i] = 'N'입니다.

내가 작성한 코드

from collections import defaultdict

def solution(weights, head2head):
    player = defaultdict(list)
    for j,h in enumerate(zip(weights, head2head), start=1) :
        ncnt = h[1].count("N")
        if len(h[1])-ncnt != 0 :
            player[j] = [h[0], h[1].count("W")/(len(h[1])-ncnt),0]
        else :
            player[j] = [h[0], 0, 0]
            

        losers = list(map(lambda z : z+1, list(filter(lambda x: h[1][x] == "W", range(len(h[1]))))))
        
        for loser in losers :
            if player[j][0] < weights[loser-1] :
                player[j][2] += 1

    return sorted(player, key = lambda x : (-player[x][1], -player[x][2], -player[x][0], x))

다음의 과정에 따라 풀이하였다.

  1. key Error를 방지하기위해 defaultdict선수번호 : [몸무게, 승률, 자신보다 몸무게가 무거운 복서를 이긴 횟수]를 담기위한 딕셔너리인 player를 생성한다
from collections import defaultdict
...

player = defailtdoct(list)
  1. j선수번호, h[0]몸무게, h[1] 은 각 선수가 치른 경기 결과, ncnt는 승률 계산을 위해 두 복서가 아직 싸우지 않은 경기를 카운트 한다. 선수 번호는 1번부터 시작하므로 start = 1을 준다.
for j,h in enumerate(zip(weights, head2head), start=1) :
        ncnt = h[1].count("N")
        if len(h[1])-ncnt != 0 :
            player[j] = [h[0], h[1].count("W")/(len(h[1])-ncnt),0]
        else :
            player[j] = [h[0], 0, 0]

여기서 ZeroDivisionError를 방지하기위해(선수들이 서로 모두 싸워보지 않은 경우) 조건문으로 나눠주었다.

  1. 복서에게 진 선수의 번호를 위해 filter로 인덱스 번호를 찾은 뒤 map 메서드로 +1씩 해준다 (인덱스는 0부터 시작하므로)
losers = list(map(lambda z : z+1, list(filter(lambda x: h[1][x] == "W", range(len(h[1]))))))
  1. 해당 복서가 자신보다 몸무게가 무거운 복서를 이겼다면 횟수를 1씩 증가시켜준다.
for loser in losers :
            if player[j][0] < weights[loser-1] :
                player[j][2] += 1
  1. 조건에 따라 정렬시켜 리턴한다.
return sorted(player, key = lambda x : (-player[x][1], -player[x][2], -player[x][0], x))

오늘의 교훈 : 난 항상 맞게 풀었다고 생각하지만, 실패는 괜히 뜨는게 아닌 법..

profile
Convinced myself, I seek not to convince.

0개의 댓글