ASAC 빅데이터 분석가 7기/ASAC 일일 기록

ASAC 빅데이터 분석가 과정 5일차 - 1 (24.12.10)

junslee 2024. 12. 10. 09:57

04_cotest

03_구현_카카오키패드

(이전 내용 포함)

프로그래머스 사이트
---> solution 함수!!!
---> 입력에 부분에 있어서는 굳이 변경을 잘 하지 않음!!!
def solution(numbers, hand):
    answer = ''
    ##########
    --> 문제에서 주어진 상황에 맞는 코드를 작성!!!!
         입력 + 주어진 상황 + 요청한 출력!!!!!
    참고) 외부 패키지 : 사용할 수 있는 리스트,,,
    참고) 다른 기능적인 부분을 외부 함수를 만들어서 호출!!
    ##########
    return answer


문제 이해를 위한 정리
- 엄지 손가락만 사용한다(왼엄, 오엄)
- 초기 위치 : L(*), R(#)
- 이동 경우 : LRUD움직(단, 대각선은 X, 수직 / 수평)
- 버튼의 종류에 따라서 case by case --> if
  1) 1,4,7 : 무조건 왼손
  2) 3,6,9 : 무존건 오른손
  3) 2,5,8,0 : 가장 가까운 거리!!!! 거리???어떻게???
    3-1) 거리가 다를 때 : 가까운 손
    3-2) 거리가 같을 떄 : 어느손 잡이

결국 solution 함수 제출
입력 : numbers --> 누를 숫자들(리스트) [ 원소수 1~1000], 0~9
          hand    --> 무슨 손 잡이(문자열) ["left", "right"]
출력 : answer  --> 문자열
                   입력으로 준 numbers에 해다하는 누른 손을 문자열!!!
                    L/R을 사용해서 이어진(공백없는)문자열!!!


거리 : 직교거리(가로로 얼마 + 세로로 얼마)
        ==> 대각선 거리X
        ==> 가로사이의 거리 + 세로 사이의 거리
        ==> 이거 최악의 경우1000개 지시사항 중에서 1/3 : 함수.

세팅 : 위치pos & 거리도 계산!!
=====> 키패드 평면 : 좌표화!!!!


큰 틀 : 눌러야 하는 버튼을 돌리면 됨!!!
for num in numbers:
    if 1/4/7:
        무조건 왼손
    elif 3/6/9
        무조건 오른손
    else/elif 2/5/8/0
        ++ 양손에서의 이 버튼 사이의 거리!!!!
        ==> 여러번 사용될 것 같음!!!! 함수!!!!
        ( 입력 : 손의위치, 누를 버튼) --> 출력 : 직선거리
        D_L, D_R
        if 거리가 다를 때:
            짧은 거리 거리 손을 선택!!!!
        else: # 거리가 같을 때
            hands 입력 변수의 정보를 사용!!!

==> 거리는 어떻게 할까??? 위치????
===> 문제에서는 대 놓고 좌표/ 축/ 기준 이런 말이 없음!!!
        : 없으면 본인 편한대로 만들면 됨!!!!(숫자로 좌표!!!!)
        : 숫자로 좌표 == 거리/ 위치


세팅 : 주어진 키패드 코드화 ==> 좌표!!! Dict
        : 초기값이 *, # 를 포함한 0~9까지 버튼을 대상!!!!
        : 키값 문자열, 값 (좌표)
   ===> 완벽한 개인 취향!!!!
key_pad = {
    "1":[0,0], "2":[0,1], "3":[0,2],
    "4":[1,0], "5":[1,1], "6":[1,2],
    "7":[2,0], "8":[2,1], "9":[2,2],
    "*":[3,0]
}

key_pad

 

(코테에서는 Dict을 선호하는 경향이 있다)


참고) 앞에서 처럼 리스트 중심의 인덱스로 한다면,,.,,
key_pad_list = ["1","2","3","4",..........]
pos_x        = [0,  0,   0,  1,,,,,,,,,,,,]
pos_y        = [0,  1,   2,  0,,,,,,,,,,,,]
pos            = [[0,0], [0,1],[0,2] ]


# * 위치에 있을 때 좌표값은?
key_pad["*"][0], key_pad["*"][1]

 

temp_x, temp_y = key_pad["*"]      (파이썬의 멀티 할당)

print(temp_x, temp_y)

 

+++ 추가적인 기능 : 거리구하는 부분 ==> 여러번 사용될 듯!!==> 함수!!!
==> 2/5/8/0 누를 때만 불러서 사용을 하려고 함!!!

입력 : 2개 키패드 위치( 눌러야 할 캐패드 번호, 현재 손 위치)
기능 : 입력 2개 위치 상에서 서로 L1/ 직선거리 / 맨하탄거리 방식으로 계산!!!
출력 : 그렇게 계산된 거리값

1-2, 2-1 : 다 양수로 나타나야 함!!!
==> abs() 함수 식을 사용해도 되고, if문으로 직접 구현해도 되고!!!!  #abs() : 절대값 함수
==> 몰라도 그냥 하면 된다


def get_distance( number, pos):
    # 입력으로 받은 number, pos변수 : 이 함수 내에서만 생존!!!!
    key_pad = {"1":[0,0], "2":[0,1], "3":[0,2],"4":[1,0], "5":[1,1], "6":[1,2],
                 "7":[2,0], "8":[2,1], "9":[2,2],"*":[3,0], "0":[3,1], "#":[3,2]}
    # 명시적으로 눌러야 할 버튼에 대한 값의 형 : 문자열로 형 변환!!  (오류를 예방)
    number = str(number)
    pos = str(pos)
    # 1) 눌러야 할 버튼의 좌표값 & 파이썬 멀티할당
    x_number, y_number = key_pad[number]
    # x_number = key_pad[number][0]
    # y_number = key_pad[number][1]
    # 2) 손의 위치에 대한 버튼의 좌표값 & 파이썬의 멀티할당
    x_pos, y_pos = key_pad[pos]
    # 3) 1번하고 2번 사이의 거리 ==> 수직거리!!!!! ===> abs함수,,,,,
    abs_distance = abs(x_number - x_pos) + abs(y_number-y_pos)
    # 최종 출력
    return abs_distance

 

# 만든 기능이 잘 동작하는지 체크!!!
get_distance("5","3")


==> 큰 틀 : 입력으로 받은 numbers를 중심으로 롤링 : for
case1) 1/4/7 : 왼손
case2) 3/6/9 : 오른손
case3) 2/5/8/0  ===> 왼손과 오른손 사이의 거리 : get_distance()
                     d_l = get_distance(~~~)
                     d_r = get_distance(~~~)
      case3-1) d_l == d_r : hand정보
      case3-2) d_l != d_r : 가까운 거리의 손 ===> 부등식 처리!!!
                    d_l < d_r : 왼손
                    d_l > d_r : 오른손


#####꼭 혼자서 해보자!!#####(정답코드)

def get_distance( number, pos):
    key_pad = {"1":[0,0], "2":[0,1], "3":[0,2],"4":[1,0], "5":[1,1], "6":[1,2],
                 "7":[2,0], "8":[2,1], "9":[2,2],"*":[3,0], "0":[3,1], "#":[3,2]}
    number = str(number)
    pos = str(pos)
    x_number, y_number = key_pad[number]
    x_pos, y_pos = key_pad[pos]
    abs_distance = abs(x_number - x_pos) + abs(y_number-y_pos)
    return abs_distance


def get_distance( number, pos):
    key_pad = {"1":[0,0], "2":[0,1], "3":[0,2],"4":[1,0], "5":[1,1], "6":[1,2],
                 "7":[2,0], "8":[2,1], "9":[2,2],"*":[3,0], "0":[3,1], "#":[3,2]}
    number = str(number)
    pos = str(pos)
    x_number, y_number = key_pad[number]
    x_pos, y_pos = key_pad[pos]
    abs_distance = abs(x_number - x_pos) + abs(y_number-y_pos)
    return abs_distance


def solution(numbers, hand):
    answer = ''
    ########
    # 1-1) 필요한 변수들을 세팅 : 왼손 위치, 오른손 위치 변수 & 초기화
    left_pos = "*"
    right_pos = "#"
    # 1-2) 필요한 변수 세팅 : 무슨손 잡이인지 --> 입력 : left/right --> 출력:L/R
    if hand =="right":
        hand = "R"
    elif hand =="left":               #양손잡이 조건이 없기 때문에 else 생략(코테 문제 특징!)
        hand = "L"
    #########
    # 2) 본격적으로 눌러야 할 버튼 롤링!!!!!
    for num in numbers:
        # 2-1) 무조건 왼손 : 1/4/7
        if num in [1,4,7]: # num==1 or num==4
            answer += "L"
            # ++ 왼손으로 눌렀으니, 왼손의 위치를 갱신!!!!***
            left_pos = num
        # 2-2) 무조건 오른손 : 3/6/9
        elif num in [3,6,9]:
            answer += "R"
            # ++ 오른손으로 눌렀으니,,,오른손의 위치를 갱신!!!
            right_pos = num
        # 2-3)  판단 : 2/5/8/0/
        elif num in [2,5,8,0]:
            # 각 손과의 거리를 계산!!! & 거리 담당 변수가 필요!!!
            dis_left = get_distance(num, left_pos)
            dis_right = get_distance(num,right_pos )
            # 2-3-1) 거리가 왼쪽이 짧을 때
            if dis_left < dis_right:
                answer += "L"
                left_pos = num
            # 2-3-2) 거리가 오른쪽이 짧을 때
            elif dis_left > dis_right:
                answer += "R"
                right_pos = num
            # 2-3-3) 거리가 동일 할 때
            elif dis_left == dis_right:
                answer += hand
                # ===> 무슨손 잡이냐에 따라서...갱신할 손의 위치가 선택!!!
                if hand =="R":
                    right_pos = num
                elif hand =="L":
                    left_pos = num

    ########
    return answer


a = [1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5]
b = "right"
solution(a,b) # LRLLLRLLRRL //LRLLLRLLRRL


##### 코드 정리
def get_distance( number, pos):
    key_pad = {"1":[0,0], "2":[0,1], "3":[0,2],"4":[1,0], "5":[1,1], "6":[1,2],
                 "7":[2,0], "8":[2,1], "9":[2,2],"*":[3,0], "0":[3,1], "#":[3,2]}
    number = str(number)
    pos = str(pos)
    x_number, y_number = key_pad[number]
    x_pos, y_pos = key_pad[pos]
    abs_distance = abs(x_number - x_pos) + abs(y_number-y_pos)
    return abs_distance

def solution(numbers, hand):
    answer = ''
    left_pos = "*"
    right_pos = "#"
    if hand =="right":
        hand = "R"
    elif hand =="left":
        hand = "L"
    for num in numbers:
        if num in [1,4,7]: # num==1 or num==4
            answer += "L"
            left_pos = num
        elif num in [3,6,9]:
            answer += "R"
            right_pos = num
        elif num in [2,5,8,0]:
            dis_left = get_distance(num, left_pos)
            dis_right = get_distance(num,right_pos )
            if dis_left < dis_right:
                answer += "L"
                left_pos = num
            elif dis_left > dis_right:
                answer += "R"
                right_pos = num
            elif dis_left == dis_right:
                answer += hand
                if hand =="R":
                    right_pos = num
                elif hand =="L":
                    left_pos = num
    return answer


04_정렬_코테용기본

주제 : 정렬!!!
==> 코테용 vs 실제 대면 면접 / 기본적인 내용들과 차이점!!!!
코테용 : 정렬과 관련된 개별적인 알고리즘이 주된 내용이 아님!!!!
       ==> 정렬만의 문제는 거의 없음!!!!
           단, 마지막이나 중간에 1~2줄 정도 필요할 때 사용!!!
       ==> 핵심 : 내가 원하는 대로 정렬 규칙을 세팅!!!!
                   + 필요한 자료형들을 구성/설정!!!!
                ( 정렬을 하기 위한 필요한 정보들을 어떻게 세팅!! )
실제 대면 면접 : 기본적인 정렬 알고리즘 차이점 & 코드로 구현!!!
      ==> 파이썬으로 구현하면 10줄 내외!!!!
      ==> for / index / 규칙 : 코드를 작성하는 기본기 파악하기 용이!!!
      ==> 알고리즘 효율성& 특징


*** 코테상에서는 알고리즘 중요한 것이 아니라!!!
==> 문제에서 제시한 기준대로 정렬할 수 있도록 구현!!!!!!
==> 정렬을 위한 정보들을 어떻게 세팅할지가 중요!!!!!!!!!

### 파이썬을 가지고 정렬하는 기본적인 기능 ###
파이썬을 가지고 정렬하는 경우 : 크게 2가지 방법
1) 리스트.sort() 메서드 : 원본이 날라감!!!!!!!
2) 파이썬 자체의 sorted() 함수 : 원본이 그대로 유지가 됨!!!!
                                 변경된 결과를 따로 할당/연결!!!!
===> 공통점 : 둘 다 사용법이 동일함!!!!!

 

**** 중요한 점 ****
위의 2가지 방식을 사용할 때 : 문제에서 요구하는 대로 정렬 기준 작성!!!!
===> 특별한 정렬 기준에 대해서 : lambda 함수로 규칙을 기술!!!
      + 코테에서는 문제 상황/조건 각양각생 ==> 연습!!!!!!!
+++ 이러한 정렬을 하기 위해서 편한 자료형/값들을 주어진 문제에서
    어떻게 세팅을 할 것인가가!!중요한 부분!!!!!


정렬 : "기준"을 가지고, 기준에 맞춰서 순서를 정리!!!!
==> 기준 : 위치, 값의 크기, 알파벳, 문자순, 성적순 ,,,,,,,,,,

참고 : 단순 순서상 재배치 : reverse()메서드/ reversed()함수
--> 주의!!!) 값의 크기 기준X , 단순 위치 기준 역순!!!!!

a = [15,22,8, 79, 10]
a

a.reverse()
a # ===> 리스트는 변경에 대한 메서드 : 원본이 바로 변경!!!!


값을 기준으로 정렬 : .sort()메서드, sorted()파이썬 기본 함수

sorted(a) # 원소의 값의 크기 기준 정렬 : 오름차순

b = sorted(a) # sorted()함수를 사용해서 변경된 값을 사용하려면 재할당!!!
b

a.sort() # 바로 정렬 기준이 a에 적용 --> 할당이 필요X
a # ==> 원본이 뭐였지;;;;;;;

 

정리)
파이썬의 리스트.sort() 메서드 : 원본이 바로 변경!!!
파이썬의 기본 함수 sorted()   : 원본이 유지가 됨!!
                                변경된 값을 사용하기 위해서는 재할당!!!

+ opt) 값에 대한 정렬 기준 : 오름/ 내림차순
--> reverse = False : 오름차순
     reverse = True  : 내림차순
     #FM적인 방법

a = [15,22,8, 79, 10]
a

a.sort(reverse =True) # 값의 크기 기준 : 내림차순
a

a.sort(reverse =False) # 값의 크기 기준 : 오름차순==>기본값
a

a = [15,22,8, 79, 10]
a

sorted( a, reverse=True) # 값 기준 내림차순


sorted( a, reverse=False) # 값 기준 오름차순

#정리
포지션 중심으로 뒤짚기 : reverse()메서드, reversed()함수
기준으로 정렬을 오름/내림 차순 : reverse파라미터 =T/F==> .sort(), sorted()


#목적 : 내가 원하는 정렬 기준을 만들어서 하자!!!!!!! ***

str_list = ["좋은하루","good morning", "굿모닝","niceday"]
str_list

참고) 수업 진행을 위해서 원본을 유지를 하는 sorted만 사용을 하겠습니다.
       .sort() 메서드가 동일하므로!!!!!

sorted(str_list) # --> 기본 정렬 : 값 & 오름차순
==> 컴퓨터의 코드값을 기준으로,,,영어가 한글보다 앞의 숫자로 할당을 했기에..

       (한글보다 영어가 먼저인 이유 : 코드값)

ord("g")

ord("n")

ord("굿")

sorted(str_list, reverse=True) # 값을 기준 / 내림차순


**********************************************************************
*** 원하는 기준대로 정렬 하는 것에 표현 : lambda 함수!!!!!!***
**********************************************************************

                 // lmabda 함수 정리 !!!! + sorted 함 정리!!!

str_list

ex) 글자의 앞글자 1개만 가지고 정렬을 하려고 함!!!!
===> 그 외의 글자들은 신경안 쓸께요!!!(그냥 원본 순서대로)

sorted( str_list, key=lambda x:x[0] )

ex) 특이하게 글자의 2번째 글자 1개만 가지고 정렬을 하겠습니다!!!
   ==> 그 외의 글자들은 신경 안 쓸께요!!!(그냥 원본 순서대로)
+++ 내가 직접 기준을 만들어야 함!!!!
sorted( str_list, key=lambda x:x[1] )

ex) 특별하게 글자의 길이순서대로 정렬해주세요!!!
===> 이것도 특별기준 : 내가 직접 만들어 내야 함!!!!!
sorted( str_list, key = lambda x: len(x))
===> 위의 코드 : 기준만 작성을 했고, 어느 순서인지 생략!!!
                                     기본이 오름차순 Default!!!

ex) 특별하게 글자의 길이에 대해서 내림차순으로 정렬해주세요!!!!
     (FM적인 방법)
sorted( str_list, key = lambda x: len(x), reverse=True)

 

오름/내림 방향성에 대해서 FM적으로는 reverse 파라미터 T/F
AM적으로으로 간단하게 +/-부호!!!!!
===> 조건이 여러개가 있는 경우에 대해서, 각 조건별로 방향성을 다 다르게 부여!!!

sorted( str_list, key = lambda x: +len(x) )   #오름차순

sorted( str_list, key = lambda x: -len(x) )    #내림차순


구체적인 예 : 이름,성적 자료형에 대해서 정렬!!!
zumsu_list = [ ("A",0), ("B",1), ("C",5), ("D",3), ("E",5)]
zumsu_list

--> 그냥 정렬해줘!!!
sorted(zumsu_list)

--> 정렬 기준 : 이름 중심으로 정렬을 해주세요!!!
sorted(zumsu_list, key=lambda x: x[0])

--> 정렬 기준 : 성적순으로 정렬을 해주세요!!!!
sorted(zumsu_list, key=lambda x: x[1])

 

*** 중요!!!!
==> 내가 기준을 지정하지 않는 상황에서 동일한 순서가 발생하면!!!!!
        "원본의 순서를 그대로 유지를 한다!!!!!!!"

==> 성적이 제일 높은 친구를 앞으로 오게 해주시고,,
       성적이 낮은 친구들을 뒤로 정렬해주세요!!!!
---> 성적이라는 기준을 내림차순: FM--> reverse=True
                                                       AM --> -부호


sorted(zumsu_list, key=lambda x: x[1], reverse=True)

 

sorted(zumsu_list, key=lambda x: -x[1])


# 조금 더 유사한 값들이 있는 경우로 세팅!!! 이름 - 성적!!!
zumsu_list = [
    ("A",0), ("B",5), ("AA",3),
    ("C",5),("B",1), ("Z", 5),
    ("D",3), ("E",5)
]
zumsu_list

--> 그냥 정렬해줘!!!!
sorted(zumsu_list)
결과 : 이름 순서대로 오름차순으로 정렬!!!!!사전순!!!!
       혹, 이름이 같은 경우가 생기면,,,,뒤에 값을 기준(성적) 오름차순
--> 결론 : 기준대로 다 순서대로 오름차순 일괄 적용을 함!!!!!

정렬 : 명확하게 정렬의 기준을 제시!!!!
      ==> 정렬의 1기준 : 이름 순서
          (혹, 정렬 1기준이 같다면(동명이인), 그냥 원본 순서대로)
sorted( zumsu_list, key = lambda x: x[0])
--> 코드적으로 정렬 기준에 안 쓰이면,,, 원본 순서를 유지!!!

정렬 : 아무것도 안 한 sorted()하고 동일하게 나오게 key, lamdba로 구현
        : 1번 정렬 기준 : 이름(오름차순)
        : 2번 정렬 기준 : 성적(오름차순)
===> lambda함수에 기술!!!!
        여러개의 정렬 기준을 작성을 하는 과정에서는 순서, () 표현!!!
sorted( zumsu_list, key=lambda x: (x[0], x[1] ))

 

*****
#보통 코테 혼재된 방향성을 사용하는 경우가 있음!!!
1정렬 기준 : 이름(오름차순)
2정렬 기준 : 성적(내림차순)
그 외에는 원본 순서대로 유지해주세요!!!!
sorted( zumsu_list, key=lambda x: (x[0], -x[1] ))

#참고 : reverse 파라미터로 하게 되면???
====> 모든 정렬 기준들이 다 같은 방향으로 움직이게 됨!!!!!!
sorted( zumsu_list, key=lambda x: (x[0], x[1] ), reverse=True)

 

sorted( zumsu_list, key=lambda x: (x[0], x[1] ), reverse=False)

 

### 코테용 입장에서 정렬 : 위의 예제들에서 이름/성적 예시!!!!ㄲ
# ===> 가장 기본적인 형식!!!
#      (이름은 오름차순, 성적은 내림차순....)
# +++ 정렬 기준에 안 적으면,,,,,원본 순서가 유지가 된다!!!!!!


05_정렬_실패율

문제를 읽으면서 끄적.;;
문제의 핵심 : 실패율의 정의대로 구해서---> 내림차순!!! : 정렬?
==> 정렬의 기준 : 실패율!!
       실패율 정의 =  스테이지를 실패한 수 / 스테이지에 도전자수
                case by case : 도전자 유저수 == 0 : 실패율 0 정의
                               도전자 유저수 != 0 : 실패율 계산...
==> 정렬을 할 때 : 실패율(내림차순) ---> 스테이지 번호(오름차순)

입력 : N --> 전체 게임의 스테이지의 수
         stages --> 이 게임 유저들이 현재 어느 스테이지에 있는지 정보(리스트)
출력 : 실패율 계산 --> 실패율에 대한 정렬(내림차순)
       --> 스테이지 번호만 리스트로 제출!!!!!

stages : 길이 1~20000까지
              값 1~~ N+1
              N+1의미 : N스테이지까지 다 클리어한 유저!!!!!


예시1)
N = 5
stages = [2, 1, 2, 6, 2, 4, 3, 3]

1stage
도전자 : 8명  --> stages의 원소의 수 8 ==> 8명이 이 게임에 참가
실패자 : 1명  --> 지금 1번에 있는 친구 수 ===> 값이 1인 갯수
실패율 : 1/8

2stage
도전자 : 7명 = 8 - 1 ( 1스테이지 도전자 - 1스테이지 실패자)
실패자 : 3명 --> 지금 2번에 있는 친구 수 ==> 값이 2인 갯수
실패율 : 3/7

3stage
도전자 : 4명 = 7 - 3 ( 2스테이지 도전자 - 2스테이지 실패자)
실패자 : 2명 --> 지금 3번에 있는 친구 수 ==> 값이 3인 갯수
실패율 : 2/4

4stage
도전자 : 2명 = 4 - 2 ( 3스테이지 도전자 - 3번 스테이지 실패자)
실패자 : 1명 --> 지금 4번에 있는 친구 수 ==> 값이 4인 갯수
실패율 : 1/2

5stage
도전자 : 1명 = 2 - 1 ( 4스테이지 도전자 - 4번 스테이지 실패자)
실패자 : 0명 ---> 지금 5번에 있는 친구 수 ==> 값이 5인 갯수
실패율 : 0/1
#####################################################
스테이지별로 실패율 정렬!!!!( 혹, 값이 같다면,,,작은 스테이지 번호!!!!!)
1F = 0.125
2F = 0.428
3F = 0.5
4F = 0.5
5F = 0
---> 3 --> 4 ---> 2 ---> 1 ---> 5


===> 생각의 시작 : i번째 stage에서 어찌될까에 대한 규칙화!!!!!

i-stages 에서
도전자 : (i-1)stage 도전자 - (i-1)stage의 실패자 ==> i-stage 도전자!!!
실패자 : 값이 i인 것들의 갯수!!!!
실패율 : i_F = i_실패자/i_도전수
          ==> i_도전자 수 ==0 : i_F = 0
                       !=0 : i_F = i_실패자/i_도전수

===> i=1에서는 i-1=0번째 스테이지 ==> 총 도전자!!!!!/ 유저 수
+++ 필요한 정보 : ( i-stage, i_F)

 


예시2)
N = 4
stages = [4,4,4,4,4] //[4,1,2,3]

1stage
도전자 : 5
실패자 : 0
1F = 0

2stage
도전자 : 5
실패자 : 0
2fF = 0

3stage
도전자 : 5
실패자 : 0
3F = 0

4stage
도전자 : 5
실패자 : 5
4F = 1

--> 4-->1->2->3


정렬의 위한 자료 정리
==> [스테이지 번호, 그 스테이지 실패율] // [ 이름, 성적]
    [(1, 1_f), (2,2_f), (3, 3_f) .....]


중요사항
===> 출력에서 정렬을 사용을 해야함!!!!!
정렬1기준) 실패율 : 내림차순
정렬2기준) 스테이지 번호 : 오름차순
-----> 기준별로 방향성이 따로 따로이니,,,,+/-로 하는게 나을 듯!!!!
+++ sorted(), .sort() +++ key + lambda + (+/-)
====> 정렬&출력에 필요한 정보 : 스테이지번호, 실패율
====> [(1, 1_f), (2,2_f), (3, 3_f) .....]

[ [1, 1/8], [2, 3/7], [3, 0.5], [4, 0.5], [5, 0]]
--> [[3, 0.5],  [4, 0.5],[2, 3/7],[1, 1/8], [5, 0] ]
===> [3,4,2,1,5]


참고!!!) 정렬에 대한 대상이 오로지 리스트만 가능할까?
==> No!!!
Dict로 정렬이 가능함!!!!!!
참고) 저는 dict로 진행을 해보겠습니다.
= {1:1/8, 2:3/7, 3:2/4, 4:1/2, 5:0}
t

===> 정렬의 1기준 : value
                     2기준 : key
t.items()

temp = sorted( t.items(), key=lambda x: ( -x[1], x[0] ) )
temp

# temp를 최종 출력용으로 정리하면 : LC
[i[0] for i in temp]

b = []
for i in temp:
    b.append(i[0])
b


# 참고) 실패자의 수 : 필터링 & 카운팅!!!!
# m1) 리스트의 메서드 : .count()
[2, 1, 2, 6, 2, 4, 3, 3].count(2)

# m2) 필터링 & 카운팅 ==> LC
a = [2, 1, 2, 6, 2, 4, 3, 3]
len([ i for i in a if i ==2])

# m3) 꾸역꾸역 하자!!!!
cnt = 0
a = [2, 1, 2, 6, 2, 4, 3, 3]
for i in a:
    if i == 2:
        cnt += 1
print(cnt)


#### 저는 여기서는 dict로 해보겠습니다..

# dict
a_dict = {}
a_dict

a_dict["a"] = 100
a_dict

a_dict["a"] = 200     # 값의 변경
a_dict

a_dict["b"] = 999     # 값의 추가
a_dict


def solution(N, stages):
    answer = []
    ######
    # 1) 필요한 정보들을 세팅!!!!
    # 1-1) 정렬을 위한 기본 정보처리 : dict ---> k:스테이지번호, v:실패율
    fail_dict = {} # --> 스테이지를 돌아가면서,,,계산 결과를 추가!!!!
    # 1-2) 최초 도전자에 대한 수  ==> 각 스테이지별로 돌아가면서 갱신!!!
    num_people = len(stages) # --> 갱신 : i_stage의 도전자수 & 처음에는 1번스테이지 도전자 초기화

    # 2) 큰 구조 : 스테이지를 돌아가면서 실패율 계산!!!!
    # ===> 1,2,3,,,,,N 숫자 중심 롤링 : range(1, N+1,1)
    for i_stage in range(1, N+1):
        # 2-1) i번째 스테이지에서 할 일
        # 2-1-1) i번째 스테이지에서 실패자 수 : 카운팅(필터링)==> .count()
        fail_num = stages.count( i_stage )
        # len( [ i for i in stages if i ==i_stage])
        # 2-2-2) 실패율!!! case by case
        if num_people > 0: # 1명 이상의 참가자 존재 --> 계산
            fail_dict[i_stage] = fail_num / num_people
        else: # 0명의 참가자 존재 => 정의 0
            fail_dict[i_stage] = 0
        # cf) 리스트로,,, fail_list.append([i_stage, fail_num / num_people])
        # 2-2-3) 다음 라운드의 참가자에 대한 정보 : 갱신!!!!!
        num_people -= fail_num
    # ---> fail_dict = {1:1/8, 2:3/7, 3:2/4, 4:1/2, 5:0}
    #-------------------------------------------------

    # 3) 출력을 위한 정리 & 정렬!!!!!
    # --> 정렬1기준 : 실패율 & 내림차순
    #     정렬2기준 : 스테이지번호 & 오름차순
    # fail_dict.items() : [ (1,1/8) , (2,3/7), (3, 0.5), (4,0.5), (5,0) ]
    #   key : x ==> (2, 3/7)
    fail_list = sorted( fail_dict.items(), key=lambda x:( -x[1], x[0]) )
    # [(3, 0.5), (4, 0.5), (2, 0.42857142857142855), (1, 0.125), (5, 0)]

    # 4) 최종 제출 양식 : 정렬된 stage 번호를 리스트로 전달...
    answer = [ fail_info[0] for fail_info in fail_list]
    # [3,4,2,1,5]
    ######
    return answer



# test
a = 5
b = [2, 1, 2, 6, 2, 4, 3, 3]# // [3,4,2,1,5]
solution(a,b)

# test
a = 4
b = [4,4,4,4,4] # // [4,1,2,3]
solution(a,b)


# 코드 정리
def solution(N, stages):
    answer = []
    fail_dict = {}     # --> 스테이지를 돌아가면서,,,계산 결과를 추가!!!!
    num_people = len(stages)       # --> 갱신 : i_stage의 도전자수 & 처음에는 1번스테이지 도전자 초기화
    for i_stage in range(1, N+1):
        fail_num = stages.count( i_stage )
        if num_people > 0:      # 1명 이상의 참가자 존재 --> 계산
            fail_dict[i_stage] = fail_num / num_people
        else:        # 0명의 참가자 존재 => 정의 0
            fail_dict[i_stage] = 0
        num_people -= fail_num
    fail_list = sorted( fail_dict.items(), key=lambda x:( -x[1], x[0]) )
    answer = [ fail_info[0] for fail_info in fail_list]

    return answer


//자료형과 정보들을 어떻게 처리할 것인지

//코드를 어떻게 간결하게 만들 것인지

 

## 정리
1. 정렬에 대한 내용이 메인이 아님!!!!
   ==> 다른 여러 알고리즘. 주제와 함께 섞여서 최종 제출부분으로 처리!!!!
       : 위의 예제는 그냥 주어진 문제를 구현하는 부분에 + 정렬
   ==> 이러한 기본적인 정렬을 하지 못하면,,,다하고 틀리느는 일이 있으니 꼭!!!
2. 정렬을 하기 위한 세팅을 어떻게 할지 : 스스로 결정& 판단!!!
   ==> 그 부분에 맞춰서, 코드 & 문법을 적당히 사용해야 함!!!!

 

==> 이 문제 정도는 기본 연습 레벨로 생각을 하고,,
       최근의 경향은 기본 구성이 좀 복잡하게& 꼼꼼하게 해야하는 것으로 업글!!!
==> ref: https://school.programmers.co.kr/learn/courses/30/lessons/92341?language=python3
       최근에는 그래도 하 난이도의 문제이지만, 이정도의 길이&지저분함을 생각하고