ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 2024-01-04
    스파르타/TIL(Today I Learned) 2024. 1. 4. 23:32
    더보기

    SQL 코드카타

    https://school.programmers.co.kr/learn/courses/30/lessons/59042

    천재지변으로 인해 일부 데이터가 유실되었습니다. 입양을 간 기록은 있는데, 보호소에 들어온 기록이 없는 동물의 ID와 이름을 ID 순으로 조회하는 SQL문을 작성해주세요.라는 문제이다.

    SELECT outs.animal_id, outs.name
    FROM ANIMAL_INS ins right join ANIMAL_OUTS outs on ins.animal_id = outs.animal_id
    WHERE outs.animal_id is not null and ins.animal_id is null
    

    처음으로 right join을 일부러 연습 겸 써보았다 out테이블에는 기록되어있는데 in 테이블에서는 없는 데이터를 조회해야하므로 where절에서 out~is not null and in~is null을 사용하여 쿼리를 작성해주었다.

     

    과일로 만든 아이스크림 고르기(SQL)

    https://school.programmers.co.kr/learn/courses/30/lessons/133025

    상반기 아이스크림 총주문량이 3,000보다 높으면서 아이스크림의 주 성분이 과일인 아이스크림의 맛을 총주문량이 큰 순서대로 조회하는 SQL 문을 작성해주세요.라는 문제이다.

    SELECT HALF.FLAVOR
    FROM FIRST_HALF HALF inner join ICECREAM_INFO INFO on HALF.FLAVOR = INFO.FLAVOR
    WHERE HALF.TOTAL_ORDER>3000 and INFO.INGREDIENT_TYPE = 'fruit_based'
    ORDER BY HALF.TOTAL_ORDER desc
    

    우선 기본키와 외래키로 주어진 FLAVOR를 이용하여 FIRST_HALF테이블과 ICECREAM_INFO테이블을 inner join하여 붙였고, 그뒤 total_order가 3000을 넘고, INGREDIENT_TYPE이 fruit_based인 데이터만 조회되도록 필터의 조건을 달아준뒤, total_order를 내림차순으로 정렬해주었다.

     

    재구매가 일어난 상품과 회원 리스트 구하기(SQL)(where 서브쿼리, having)

    https://school.programmers.co.kr/learn/courses/30/lessons/131536

    ONLINE_SALE 테이블에서 동일한 회원이 동일한 상품을 재구매한 데이터를 구하여, 재구매한 회원 ID와 재구매한 상품 ID를 출력하는 SQL문을 작성해주세요. 결과는 회원 ID를 기준으로 오름차순 정렬해주시고 회원 ID가 같다면 상품 ID를 기준으로 내림차순 정렬해주세요.라는 문제이다.

    SELECT USER_ID,PRODUCT_ID,SALES_DATE
    FROM ONLINE_SALE main
    ORDER BY USER_ID,SALES_DATE
    

    우선 위의 코드로 대략적인 데이터가 어떻게 있는지 확인용 쿼리를 작성해두고 결과가 이상하거나 할 시 쓰기 위해 따로 복사해뒀다

    SELECT USER_ID, PRODUCT_ID
    FROM ONLINE_SALE sub
    GROUP BY USER_ID,PRODUCT_ID
    HAVING COUNT(PRODUCT_ID)>1
    

    그 뒤 where절에서 필터의 조건이 될 서브쿼리문을 작성해주었다

    우선 ONLINE_SALE테이블에서 데이터를 가져온 뒤 user_id와 product_id에 대하여 그룹으로 묶어주었다. 그뒤 각 그룹에 대하여 상품id가 1개보다 큰 데이터에 대해서만 보여달라는 것이고 유저id와 상품id를 최종적으로 컬럼으로써 보여준다. (그런데 HAVING COUNT(PRODUCT_ID)>1부분이 조금 헷깔리긴 하다 그룹을 오직 유저id로만 묶을 경우에는 유저id에 대하여 그 아이디로 주문한 상품id들의 갯수를 세개 되는데, 유저id와 상품id 순서대로 같이 묶을 경우에는 그 상품id가 각자 몇개 있냐는 확인 개념으로 갯수를 파악해서 그런듯하다)

    SELECT USER_ID, PRODUCT_ID, count(product_id)
    FROM ONLINE_SALE sub
    GROUP BY USER_ID
    #HAVING COUNT(PRODUCT_ID)>1
    

    위 쿼리는 유저id에 대해서만 그룹짓고 count상품id를 했을 경우이다.

    SELECT USER_ID, distinct PRODUCT_ID
    FROM ONLINE_SALE main
    WHERE (SELECT PRODUCT_ID FROM ONLINE_SALE sub
            GROUP BY USER_ID,PRODUCT_ID
            HAVING COUNT(PRODUCT_ID)>1
                    and sub.USER_ID=main.USER_ID)
    ORDER BY USER_ID#, PRODUCT_ID desc
    

    그 뒤 위에서 작성한 쿼리문으로 컬럼을 상품id만 되게 해준 뒤(where절에 서브쿼리문을 사용시에 매번 이런식으로 컬럼을 한개만 가지도록 해줘야 작동했던 것 같다. 아닌 경우에 대해서는 아직도 확신이 조금 부족해서 좀 더 테스트 해봐야 할듯 하다)

    그 뒤 처음으로 생각할 때는 기본적으로 생각하고 있던 메인쿼리에 대하여 작성해 주었는데 우선 같은 테이블에서 데이터를 가져오고 작성해준 서브쿼리문에서 상품id에 대하여 여러 번 존재하는 경우에 대해서만 데이터를 가져오며 유저id와 중복되지 않는 상품id를 가져왔는데 이 경우에는 에러가 났다 (중복되지 않는 상품id를 가져온 이유는 그냥 상품id를 가져왔을 경우에는 존재하는 여러 개의 중복된 유저id-상품id를 가져왔기 때문이다(따로 추가 조건 등을 넣어 주지 않고 그냥 해당 하는 데이터 다 가져왔으니 여러 개 있는대로 여러 개가 나타나는게 당연하다) 하지만 지금 원하는 것은 유저id별로 재구매한 상품id 종류를 보고 싶은 것이니 한 번만 출력되게 하고 싶었다 그러하여 우선 상품id에 중복되지 않는을 넣으면 되지 않을까 생각하였는데, 잘못한 생각 이였는 듯하다 아직 에러의 이유는 파악하지 못하였다)-having절에 추가로 and sub.PRODUCT_ID=main.PRODUCT_ID 를 붙여줘도 똑같이 에러가 났다.

    SQL 실행 중 오류가 발생하였습니다.
    You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'distinct PRODUCT_ID
    FROM ONLINE_SALE main
    WHERE (SELECT PRODUCT_ID FROM ONLINE_S' at line 2
    

    째든 좀 더 생각해보니 유저 아이디를 중복없이 나오게 한다면 충분히 원하는 결과를 얻을 것 같아 다음과 같이 수정해주었다 where절에서 서브쿼리와 메인쿼리에 대해 상품id도 서로 연결해주었는데, 만약 붙이지 않을 경우 아래와 같이 에러가 나기 때문이였다 코드 실행은 되는데 제출 후 채점이 안되는 이유에 대해서는 처음 겪어보는 상황이라 이유가 짐작이 가는게 없어서 우선 넘기고 다른부분하고 다시 생각해봐야할듯하다(우선 질문하기에 올려두었다)

    SELECT distinct USER_ID, PRODUCT_ID
    FROM ONLINE_SALE main
    WHERE (SELECT PRODUCT_ID FROM ONLINE_SALE sub
            GROUP BY USER_ID,PRODUCT_ID
            HAVING COUNT(PRODUCT_ID)>1
                    and sub.USER_ID=main.USER_ID and sub.PRODUCT_ID=main.PRODUCT_ID)
    ORDER BY USER_ID, PRODUCT_ID desc
    

     이 쿼리가 최종 제출 쿼리이다.

     

    SELECT distinct USER_ID, PRODUCT_ID
    FROM ONLINE_SALE main
    WHERE (SELECT PRODUCT_ID FROM ONLINE_SALE sub
            GROUP BY USER_ID,PRODUCT_ID
            HAVING COUNT(PRODUCT_ID)>1
                    and sub.USER_ID=main.USER_ID)
    ORDER BY USER_ID, PRODUCT_ID desc
    #and sub.PRODUCT_ID=main.PRODUCT_ID 안붙이면 코드실행은 되지만 제출후 채점하기를 누를시 에러가 뜸
    #SQL 실행 중 오류가 발생하였습니다.
    #Subquery returns more than 1 row
    

    그리고 추가 여담으로 깜박하고 안 쓴 것 이였는데, where절에서 서브쿼리문만 넣고 조건이라고 할 수 있는 PRODUCT_ID = 를 빼먹었는데 넣기 전이나 넣은 후나 에러 등을 포함하여 결과가 달라지는 것이 없었다 그래서 이 부분에 대하여 원래 굳이 넣을 필요가 없는 것인지, 아니면 작동은 하지만 별로 좋은 것이 아니라 피해야 하는 일인지 확인을 해볼 필요가 있을 듯하다

    SELECT distinct USER_ID, PRODUCT_ID
    FROM ONLINE_SALE main
    WHERE PRODUCT_ID = (SELECT PRODUCT_ID FROM ONLINE_SALE sub
            GROUP BY USER_ID,PRODUCT_ID
            HAVING COUNT(PRODUCT_ID)>1
                    and sub.USER_ID=main.USER_ID and sub.PRODUCT_ID=main.PRODUCT_ID)
    ORDER BY USER_ID, PRODUCT_ID desc
    

     

    74번 특정 기간동안 대여 가능한 자동차들의 대여비용 구하기(SQL) (with, round, join, where, having, max, date 날짜 데이터 필터 조건 및 형식?)

    아직 순서대로 풀 때 풀 차례가 아니긴 했으나, 팀원분께서 푸실 때 어렵다고 하셔서 도움이 될까 싶어 먼저 풀어보았다

    https://school.programmers.co.kr/learn/courses/30/lessons/157339

    CAR_RENTAL_COMPANY_CAR 테이블과 CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블과 CAR_RENTAL_COMPANY_DISCOUNT_PLAN 테이블에서 자동차 종류가 '세단' 또는 'SUV' 인 자동차 중 2022년 11월 1일부터 2022년 11월 30일까지 대여 가능하고 30일간의 대여 금액이 50만원 이상 200만원 미만인 자동차에 대해서 자동차 ID, 자동차 종류, 대여 금액(컬럼명: FEE) 리스트를 출력하는 SQL문을 작성해주세요. 결과는 대여 금액을 기준으로 내림차순 정렬하고, 대여 금액이 같은 경우 자동차 종류를 기준으로 오름차순 정렬, 자동차 종류까지 같은 경우 자동차 ID를 기준으로 내림차순 정렬해주세요. 라는 문제이다

    우선 필터를 요금 계산에 먼저 초점을 두어 차 종류에 따라, 대여기간에 따라 할인이 적용이 잘 되는지 먼저 테스트 해봤다

    SELECT disc.CAR_TYPE,DURATION_TYPE, disc.DISCOUNT_RATE,
        30*rental.DAILY_FEE month_FEE,
        round(30*rental.DAILY_FEE*(1-disc.DISCOUNT_RATE/100)) FEE
    FROM CAR_RENTAL_COMPANY_DISCOUNT_PLAN disc join CAR_RENTAL_COMPANY_CAR rental on disc.CAR_TYPE = rental.CAR_TYPE 
    where disc.DURATION_TYPE = '30일 이상'# and disc.CAR_TYPE = rental.CAR_TYPE
    

     이 쿼리는 요금계산관련 쿼리이다.

    SELECT disc.CAR_TYPE,DURATION_TYPE, disc.DISCOUNT_RATE,
        30*rental.DAILY_FEE month_FEE,
        30*rental.DAILY_FEE*round((1-disc.DISCOUNT_RATE/100)) FEE
    FROM CAR_RENTAL_COMPANY_DISCOUNT_PLAN disc join CAR_RENTAL_COMPANY_CAR rental on disc.CAR_TYPE = rental.CAR_TYPE 
    where disc.DURATION_TYPE = '30일 이상'# and disc.CAR_TYPE = rental.CAR_TYPE
    

    그런데 처음에 할 때 이런 식으로 소수점이 먼저 나오는 부분에 대해서만 round를 해주고 곱하였는데 round한 부분을 무시하는 것을 확인하였다. 현재 이유는 모르겠다  관련해서 알려진게 있는가 해서 round 무시, round 버그 등의 검색어로 검색해보았지만, 해당 내용은 찾아볼 수 없었다. 내일 내용을 정리하여 튜터님께 질문해보아야 할 듯하다.

    27 SUV 655500 2022-09-25 00:00:00 2022-12-24 00:00:00
    
    18 SUV 627000 2022-10-25 00:00:00 2023-01-26 00:00:00
    

     나와서는 안되는 car_id에 속하는 둘이 계속 나와서 start_date와 end_date값을 따로 적어둔 내용이다

    그러고서 처음에는 데이터를 잘못 이해해서 start_date와 end_date가 대여 가능한 시작 날짜, 끝 날짜인 줄 알고 그렇게 필터를 걸어서 했다가 대여한 날짜의 시작 날짜와 끝 날짜인데 잘못 이해했음을 깨닫고 끝 날짜가 2022-11-01이전 이거나 시작 날짜가 2022-11-31이후 인 데이터들이 조회 되도록 필터링 걸어주었으나 car_id가 중복해서 여러 개 나오고, 뭔가 날짜가 2022-11-01이전에 빌려, 2022-11-31이후에 반납한다고 되어 있는 차량에 대해서도 나오길래 뭔가 이상해서 데이터를 전체 시작 날짜, 끝 날짜에 대하여 같이 출력 되게 한 뒤에, 확인해본 결과 진실을 깨달을 수 있엇다. 생각해보면 문제 내용을 보고도 예상했어야 했었는데, 실제로 대여하고 반납하면 한 대여 대상에 대하여 대여해간 날짜, 반납한 날짜가 여러 번 생기는 것이 당연했다. 따라서 그 사실을 인지한 뒤, 문제에서 11월1일 부터 빌린다는 정보에 근거하여 아마 22년 10월31일까지만 빌려간 기록이 있고 데이터의 시점이 22년 11월 1일에 이제 대여가능한 차량이 있는 지 등 관련하여 조회할 때 볼 수있는 데이터라고 판단된다. (확인해본 결과 대여시작날짜는 예상과 같이최대 22년 10월 31일이였다.) 따라서 날짜 필터를 우선 해당 차량들에 대하여 가장 최근 기록 만을 확인해야 할 필요가 있으므로 max(end_date)를 하여 사용하여 가장 최근 기록만을 비교하도록 했는데 여기서 문제가 하나 생겼었다 먼저 원래 where절에서 date_format(컬럼,’%Y-%m-%d’)=’날짜’이런 식으로 했었는데 max함수를 사용하려고 하니 컬럼에 max(end_date)를 넣으면 되나 싶어서 넣었더니 에러가 발생하였고, date_format전체에 max함수를 써봐도 에러가 났었다

    그래서 어떻게 해야하나 고민하다가 그냥 무지성으로 max(end_date)=’날짜’로 해주니 잘 적용되었고 해결할 수 있엇다. 아직도 날짜를 필터로 할 때는 확실히 모르는 듯하여 날짜를 조건으로 하는 법에 대해서 공부와 확인, 테스트가 더 필요할 듯 하다(그리고 어느 정도 정리와 확인이 끝났는데도 불확실한 부분이 있다면 질문을 해볼 생각이다)

    그리고 그냥 되길래 혹시나 컬럼의 속성이 char이나 varchar형태인가 해서 확인해보니 date형식이 맞았다

    show COLUMNS
    from CAR_RENTAL_COMPANY_RENTAL_HISTORY
    

    째든 최종적으로 아래와 같이 쿼리를 작성하였고 해결되었다

    WITH CANDIATE_LIST as(
        SELECT rental.CAR_ID, rental.CAR_TYPE,
            round(30*rental.DAILY_FEE *(1-(SELECT disc.DISCOUNT_RATE FROM CAR_RENTAL_COMPANY_DISCOUNT_PLAN disc where disc.DURATION_TYPE = '30일 이상' and disc.CAR_TYPE = rental.CAR_TYPE)/100)) FEE
    FROM CAR_RENTAL_COMPANY_CAR rental
        join CAR_RENTAL_COMPANY_RENTAL_HISTORY history
        on rental.CAR_ID = history.CAR_ID
    WHERE rental.CAR_TYPE in ('세단','SUV') 
    GROUP BY rental.CAR_ID
    HAVING max(END_DATE)<'2022-11-01'
    )
    SELECT distinct c_list.CAR_ID, c_list.CAR_TYPE, c_list.FEE
    FROM CANDIATE_LIST c_list
    WHERE c_list.FEE BETWEEN 500000 and 1999999
    ORDER BY c_list.FEE desc, c_list.CAR_TYPE, c_list.CAR_ID desc
    

     

     풀고나서 따로 말씀드릴 시간이 없이 저녁시간 후 바로 특강이 있어서 특강이 끝나고 잠깐 모여서 얘기가 나왔을 때 완전히는 아니지만 얼추 이해되서 해결은 했다고 하셔서, 데이터를 통채로 보고 파악한 바로 실제 대여기록처럼 여러 번의 대여기록이 있으며 데이터에 2022-11-01이후로 start _date가 없기에  각 car_id에 대하여 그 이전에 end_date인 차들에 대하여만 필터를 걸어주면 된다고 말씀드리니 !!하셨다

    비록 나도 헷깔려서 시간을 많이 소비하긴 했지만 어려운 것을 명확..?(비록 왜 오류가 나는지 등에 대해 해결이 안되는 부분들이 몇 개 있지만 문제에 대하여는 명확히 어떤 내용이며, 어떻게 쿼리를 작성해야하는지는 꺠달았기에 명확이라고 봐도 되지 않을까 싶다..)하게 풀고나니 뿌듯하기도 하고, 팀원분께 도움을 줄 수 있어서 좋았다

     

    더보기

    파이썬 코드카타

    귤 고르기(python)(딕셔너리 dictionary, while, max, 컴프리헨션 관련 내용)

    https://school.programmers.co.kr/learn/courses/30/lessons/138476

    대략적으로 크기가 다른 귤들이 있는데 박스에 k개를 골라 넣을 때 크기가 최대한 같은 애들로만 넣어서 박스 안에 들어있는 귤들의 크기 종류가 최소로 할 때 그 최소 종류를 리턴해라는 문제이다.

    def solution(k, tangerine):
        num_check={} #크기별 몇개있는지 기록
        box=[] #가상의 진짜 박스
        answer = 0
        for size in tangerine: #크기별로 몇 개씩 있는지 저장
            if size in num_check:
                num_check[size] += 1
            else:
                num_check[size] = 1
                
        std=max(num_check.values()) #standard 넣을 귤 갯수 기준
        while len(box)<k:
            for key in num_check:
                if num_check[key]==std:
                    box.extend([i for i in range(num_check[key])])
                    answer+=1
                    if len(box) >=k:
                        break
            std-=1
            if std<=0: #혹시나 더이상 넣을 것이 없으면 중단
                print("더 넣을 것이 없는데요")
                break
        
        return answer
    

    우선적으로 가지고 있는 귤들의 크기와 그에 따른 갯수를 딕셔너리 형태로 저장해주었다.

    그 뒤 갯수가 가장 많은 사이즈를 첫 기준으로 잡아준다

    이제 가상의 박스에 진짜로 귤들을 넣는데 기준과 같은 갯수의 귤을 박스에 넣는다. 넣고 한 사이즈 종류에 대해 넣었으니 종류를 확인하는 값을 1증가 시켜준다. 그리고 넣었을 때 넣을려고 한 갯수 k가 이상이면 그만하고 멈춘다. 아직 부족하면 똑같이 기준에 맞는 갯수의 사이즈가 있는지 확인하고 있다면 똑같이 반복하고 없다면 기준보다 1개 적은 갯수에 대하여 동일하게 반복해준다. 이 반복을 박스에 k개이상의 귤이 들어갈 때까지 반복해준다. 그리고 혹시 모를 오류를 방지하기 위해 더 이상 넣을 것이 없어 기준이 0이하가 되면 while문을 멈춰준다 (사실 이 부분은 입력값을 제대로 넣어줬다면 필요없을 것이라 판단 되는 부분이다)

    아이디어는 어떻게 해야지 생각보다 빨리 짜였지만 처음 딕셔너리를 컴프리헨션 형식으로 해볼려고 하다가 시간을 조금 쓰고, 딕셔너리의 max함수 확인한다고 조금 시간 쓰고, 매번 쓸때마다 조심조심하게 되는 while문을 조심조심쓰다보니 생각보다는 시간이 조금 걸렸다(그럼에도 while문으로한 이유는 몇 번 해야할지 정확히 알거나 많이 해도 몇 번이 정해져 있으면 for문이 편하고 좋다 생각하지만 그렇지 않고 특정 조건이 만족될 때까지 알 수 없는 횟수를 반복할 때는 while문이 더 좋다고 생각하기 때문이다).

    t_dict={'a': 2,'b':3,'c': 2, 'd':5, 'e' : 1}
    >>> 'd' in t_dict
    True
    >>> 'h' in t_dict
    False
    >>> 3 in t_dict
    False
    >>>
    

     딕셔너리에 관하여 in을 쓰면 안에 key들에 대하여 확인이 가능하며, 

     딕셔너리 컴프리헨션 방식으로 위의 for문으로 딕셔너리 내용을 업데이트 해준 것처럼 해볼려고 알아보았으나,

    방식자체는 컴프리헨션 내에서 else를 쓸때는 if를 왼쪽에 먼저 써야하며, if를 왼쪽에 쓸려면 무조건 else와 같이 사용해야한다는 방법으로 형식은 아래와 같아 썼지만

    tangerine=[1, 3, 2, 5, 4, 5, 2, 3]
    num_check = {size: num_check[size] + 1 if size in num_check else 1 \\
    for size in tangerine} #크기별로 몇 개씩 있는지 저장
    print(num_check)
    
    >>>{1: 1, 3: 1, 2: 1, 5: 1, 4: 1}
    

    이런 형태로 컴프리헨션을 쓰면 되지 않을까 해서 썻는데 모든 value가 1로 기록되었다

     chatGPT를 통해 이유에 대해 물어보니 chatGPT물음과 답변 대강 아직num_check이 정의 되기 전인데 num_check를 참조해서 그렇다는 말을 하였고 타당한 듯하였기에 아쉽지만 컴프리헨션 방식은 포기하고 위 제출한 코드처럼 for문으로 하였다.

    그리고 딕셔너리에 대한 max함수에 대하여

    그냥딕셔너리에 대하여 max를 쓰면 key 중에 제일 큰 값나오는듯 하다

    t_dict={'a': 2,'b':3,'c': 2, 'd':5, 'e' : 1}
    >>> max(t_dict) #key들중 가장 큰값
    'e'
    >>> max(t_dict.values()) #value들중 가장 큰값
    5
    >>>
    

     테스트 해본 결과는 위와 같다.

    그리고 연산을 줄이기 위해 리스트에 한번에 여러개의 원소를 넣을 필요가 있었는데

    list에 원소 여러개 한번에 추가할 때 extend를 사용하면 된다

    >>> my_list
    [0, 2, 1, 4, 1, 0, 3, 5]
    >>> my_list.extend(10,12,13,15)
    Traceback (most recent call last):
      File "<pyshell#1>", line 1, in <module>
        my_list.extend(10,12,13,15)
    TypeError: extend() takes exactly one argument (4 given)
    >>> my_list.extend([10,12,13,15]0)
    SyntaxError: invalid syntax
    >>> my_list.extend([10,12,13,15])
    >>> my_list
    [0, 2, 1, 4, 1, 0, 3, 5, 10, 12, 13, 15]
    >>> a=[1 for i in range(4)]
    >>> my_list.extend(a)
    >>> my_list
    [0, 2, 1, 4, 1, 0, 3, 5, 10, 12, 13, 15, 1, 1, 1, 1]
    >>>
    

     사용 방식은 위와 같다

     

    그리고 추가 여담으로 while문을 처음 테스트할때는 무한loop에 빠질 위험 때문에 살짝 긴장하면서(사실 강제중지 시키면되서 큰 문제는 아니지만, 개인적으로 코딩하는 단계에서는) 하지만 꽤 자주 처음 테스트 할떄는 무한루프 방지용으로 매번 자주 사용하는 방식을 한번쯤은 기록해두면 좋을듯 하여 아래에 기록하였다.

    save = 100
    while 조건문:
    	필요한 구문들
    	save-=1
    	if save == 0 :
    		break
    

     일정 횟수를 정해두고 반복문이 시행될때마다 1씩 줄여서 0이되면 강제로 반복문을 그만두게 하는 방식이다.

    그리고 오늘은 저녁에 특강이 있었는데 학습법과 취업관련 준비에 관해서 들었다 내용이 워낙 관심을 크게 가지지 못하여 생소한 이름들이 많아 녹화강의를 보면서 추가로 정리해야 할듯하다. 처음 강의 시작하실 때 내부 자료이니 외부공유는 되지 않게 자제해달라고 하셔서 이 부분에 대해서는 일단은 혼자 따로 정리해서 보면서, 나중에 나도 누군가에게 조언해줄 수 있는 정도가 된다면 한 번쯤 정리해서 현재의 나와 같은 상태의 사람들에게 도움을 줄 수 있다면 좋을 것 같다.

     

    그리고 파이썬 문법 기초 강의도 들었는데 원래 어느정도 파이썬을 알고 있었기에 대부분 쉬운 내용이라 편하게 들었고, 마지막 기초중 심화에 속하는 내용은 알고는 있었지만 잘 쓸일이 없어서 잊어버리거나 자세히는 모르는 부분도 있었고, 아예 접할 일 자체가 없어서 모르고 있던 내용도 있었다(f-string!!이런게 있는 줄도 몰랐다.. 처음 배울 당시에는 일일히 ''붙이고 +붙여서 print해줬었기 때문에..ㅠㅠ)

    그리고 pycharm은 전에 다른 강의를 듣다가 설치는 해주었었지만 약간은 또 사용법을 배울 수 있었다 좀더 자세한 사용법을 배울 수 있었다면 좋았겠지만 메인이 아니였으니 아쉽지만 어쩔 수 없었다. 그래도 따로 배우면 되지만 막상 그렇게 하기엔 아직 기본 파이썬의 idle로 코딩하는게 익숙한 탓에 더 편해서 다른 큰 장점을 인지하기 전까진 굳이 따로 공부할 정도는 아닌 듯하여 다음 기회나 동기가 생긴다면 그때 할 계획이다.

    더보기

    파이썬 문법 기초 (문법 뽀개기)

     

    특별한 자료형으로 참/거짓을 나타내는 불(Boolean) 자료형이 있음

    #참,거짓 데이터형식을 뭐라고 하는지 잊고있었기에 기록으로 남겨두었다

    x = True   # 참
    y = False  # 거짓
    
    # 소문자로 쓰면 자료형으로 인식하지 않고 변수명이라 생각해 에러가 납니다~
    z = true   # name 'true' is not defined
    
    True = 1   # True/False는 변수명으로 쓸 수 없어요!
    

     

    #그리고 이 함수도 이번에 처음 알게 되었는데 enumerate() 사용하면 리스트에서 원소의 인덱스와 값을 같이 리턴해주는 함수라고 한다.

     

    집합 (set)

    집합은 말 그대로 '집합'을 구현하는 방법! 좋은점: 중복이 제거된다

    a = [1,2,3,4,5,3,4,2,1,2,4,2,3,1,4,1,5,1]
    
    a_set = set(a)
    
    print(a_set)
    

    교집합 / 합집합 / 차집합도 구할 수 있다

    a = ['사과','감','수박','참외','딸기']
    b = ['사과','멜론','청포도','토마토','참외']
    
    print(a & b)  # 교집합
    print(a | b)  # 합집합
    
    #차집합은 그냥 - 쓰면 됨
    

     

    f-string

    1. 변수로 더 직관적인 문자열 만들기

    예를 들어 아래 for문을 살펴보보면

    scores = [
        {'name':'영수','score':70},
        {'name':'영희','score':65},
        {'name':'기찬','score':75},
        {'name':'희수','score':23},
        {'name':'서경','score':99},
        {'name':'미주','score':100},
        {'name':'병태','score':32}    
    ]
    

    이름과 점수를 모두 출력해보면

    for s in scores:
        name = s['name']
        score = str(s['score'])
        print(name,score)
    

    아래와 같이 출력하였었는데

    for s in scores:
        name = s['name']
        score = str(s['score'])
        print(name+'는 '+score+'점 입니다')
    

    f-stirng을 이용하면 훨씬 간단하게 가능했다!

    for s in scores:
        name = s['name']
        score = str(s['score'])
        print(f'{name}은 {score}점입니다')
    

     

    예외처리

    1. try - except 문

    에러가 있어도 건너뛰게 할 수 있는 방법

    people = [
        {'name': 'bob', 'age': 20},
        {'name': 'carry', 'age': 38},
        {'name': 'john', 'age': 7},
        {'name': 'smith', 'age': 17},
        {'name': 'ben', 'age': 27},
        {'name': 'bobby', 'age': 57},
        {'name': 'red', 'age': 32},
        {'name': 'queen', 'age': 25}
    ]
    
    for person in people:
        if person['age'] > 20:
            print (person['name'])
    

    그런데 만약, bobby가 age를 갖고 있지 않다면? - 데이터 하나가 잘못되어있는 상황

    people = [
        {'name': 'bob', 'age': 20},
        {'name': 'carry', 'age': 38},
        {'name': 'john', 'age': 7},
        {'name': 'smith', 'age': 17},
        {'name': 'ben', 'age': 27},
        {'name': 'bobby'},
        {'name': 'red', 'age': 32},
        {'name': 'queen', 'age': 25}
    ]
    
    for person in people:
        if person['age'] > 20:
            print (person['name'])
    

    그 때 아래와 같이 try except 구문을 이용하면 에러를 넘길 수 있다.

    for person in people:
        try:
            if person['age'] > 20:
                print (person['name'])
        except:
            name = person['name']
            print(f'{name} - 에러입니다')
    

     

    한줄의 마법

    1. if문 - 삼항연산자

    만약 조건에 따라 다른 값을 변수에 저장하고 싶다면?

    #이 방식도 몇번 보기는 했는데 익숙하지 않아 한번도 실제로 써보지는 못했으니 다음에 써볼 기회가 있다면 써볼 생각이다.

    num = 3
    
    if num%2 == 0:
        result = "짝수"
    else:
        result = "홀수"
    
    print(f"{num}은 {result}입니다.")
    

    이것을 한 줄에 적는 것이 파이썬의 유일한 삼항연산자인 조건식이다.

    num = 3
    
    result = "짝수" if num%2 == 0 else "홀수"
    
    print(f"{num}은 {result}입니다.")
    

     

    (참일 때 값) if (조건) else (거짓일 때 값)으로 항이 3개라 삼항 연산자

    1. for문 - 한방에 써버리기

    a_list의 각 요소에 2를 곱한 새로운 리스트를 만들고 싶다면?

    a_list  = [1, 3, 2, 5, 1, 2]
    
    b_list = []
    for a in a_list:
        b_list.append(a*2)
    
    print(b_list)
    

    이것을 한 번에 쓰면 다음과 같다

    a_list  = [1, 3, 2, 5, 1, 2]
    
    b_list = [a*2 for a in a_list]
    
    print(b_list)
    

     

    map, filter, lambda식

    1. map - 리스트의 모든 원소를 조작하기
    people = [
        {'name': 'bob', 'age': 20},
        {'name': 'carry', 'age': 38},
        {'name': 'john', 'age': 7},
        {'name': 'smith', 'age': 17},
        {'name': 'ben', 'age': 27},
        {'name': 'bobby', 'age': 57},
        {'name': 'red', 'age': 32},
        {'name': 'queen', 'age': 25}
    ]
    

    1차 조작

    def check_adult(person):
        if person['age'] > 20:
            return '성인'
        else:
            return '청소년'
    
    result = map(check_adult, people)
    print(list(result))
    

    2차 조작!

    def check_adult(person):
        return '성인' if person['age'] > 20 else '청소년'
    
    result = map(check_adult, people)
    print(list(result))
    

    3차 조작!

    result = map(lambda x: ('성인' if x['age'] > 20 else '청소년'), people)
    print(list(result))
    
    1. filter - 리스트의 모든 원소 중 특별한 것만 뽑기

    map과 아주 유사한데, True인 것들만 뽑기! (map보다 훨씬 쉬움)

    result = filter(lambda x: x['age'] > 20, people)
    print(list(result))
    

     

    함수 심화

    1. 함수의 매개변수

    이 내용들은 직접 쓰는 것보단 알고 있으면 내장함수 등을 사용할 때 도큐먼트를 읽는 데 도움됨

    함수에 인수를 넣을 때, 어떤 매개변수에 어떤 값을 넣을지 정해줄 수 있음. 순서 상관 없음!

    def cal(a, b):
        return a + 2 * b
    
    print(cal(3, 5))
    print(cal(5, 3))
    print(cal(a=3, b=5)) #이런식으로 해주면 넣는 순서 신경안쓰고 넣을 수 있음
    print(cal(b=5, a=3))
    

    특정 매개변수에 디폴트 값을 지정해줄 수 있음.

    def cal2(a, b=3): #안 넣었을 때 default값
        return a + 2 * b
    
    print(cal2(4))
    print(cal2(4, 2))
    print(cal2(a=6))
    print(cal2(a=1, b=7))
    

    입력값의 개수를 지정하지 않고 모두 받는 방법!

    def call_names(*args):
        for name in args:
            print(f'{name}야 밥먹어라~')
    
    call_names('철수','영수','희재')
    

     

    이렇게 여러 개의 인수를 하나의 매개변수로 받을 때 관례적으로 args라는 이름을 사용. arguments라는 뜻

    키워드 인수를 여러 개 받는 방법!

    def get_kwargs(**kwargs):
        print(kwargs)
    
    get_kwargs(name='bob')
    get_kwargs(name='john', age='27')
    

     

    클래스

    1. 우선, 클래스를 언제 사용하는지 생각보면

    예를 들어, 아주 많은 몬스터들의 HP를 관리해야 하면 어떻게 해야 편할까?

    방법1. → 리스트의 순서를 잘 지켜서 각 몬스터들의 hp를 잘 적어둔다.

    방법2. → 몬스터마다 각자의 hp를 가질 수 있게 한다.

    몬스터 각각 마다 관리하는게 직관적이고 관리 편함 물체에 다가 물체에 관련된 속성들을 넣어두고 컨트롤 할 수 있는 함수들을 만들어서 붙여두고 가운데(중앙)에서는 함수만 불러다가 물체를 제어하는 방식 →객체지양적

    1. 클래스의 사용 방법을 눈으로 살펴보면
    class Monster():
        hp = 100
        alive = True
    
        def damage(self, attack):  #self가 대강 클래스 내에서 자기자신? 그런 의미로 보면될듯
            self.hp = self.hp - attack
            if self.hp < 0:
                self.alive = False
    
        def status_check(self):
            if self.alive:
                print('살아있다')
            else:
                print('죽었다')
    
    m1 = Monster()
    m1.damage(120)
    
    m2 = Monster()
    m2.damage(90)
    
    m.status_check()
    m2.status_check()
    

    이 때 m1, m2를 인스턴스라고 함 (각각의 객체라는 느낌?)

    그리고 마지막으로 원래 오늘 SQL 특강 관련해서 다 정리할 생각이였는데... 코드카타가 생각보다 시간을 너무 많이 잡아먹었다... 몇 문제 풀지도 못했는데... 뭐.. 오후시간 조금 남았을 때 집중이 잘 안되서 녹화부분 다시 듣고 할 자신이 없어서 우선 쉬워보이는 파이썬 개인과제부터 다풀어보느라 시간을 더 쓰긴 했지만... 그래도 내일은 특강도 따로 없고 원래 파이썬 개인과제를 다할 예정이였는데 미리 완성은 아니지만 거의 끝내놨으니 그 시간에 SQL얼른 정리하고 질문할 거리들 정리해서 질문해야 할듯하다.

    '스파르타 > TIL(Today I Learned)' 카테고리의 다른 글

    2024-01-06~2024-01-07  (1) 2024.01.08
    2024-01-05  (1) 2024.01.05
    2024-01-03  (2) 2024.01.03
    2024-01-02  (1) 2024.01.02
    2023-12-30~2023-01-01  (0) 2024.01.02
Designed by Tistory.