본문 바로가기

개발일지/TIL

TIL 23-04-26 팀원과의 코드리뷰 - 수박수박수박수박수박수?

1. 프로그래머스 기초 트레이닝 - 길이에 따른 연산 

 문제점

문제 설명
정수가 담긴 리스트 num_list가 주어질 때, 
리스트의 길이가 11 이상이면 리스트에 있는 모든 원소의 합을 10 이하이면 
모든 원소의 곱을 return하도록 solution 함수를 완성해주세요.

제한사항
2 ≤ num_list의 길이 ≤ 20
1 ≤ num_list의 원소 ≤ 9

# num_list = 정수가 담긴 리스트
 # return은  num_list의 길이가 11 이상이면 원소의 합을, 아니면 원소의 곱을 리턴

 시도해 본 것들

sum, if문, for문 사용

def solution(num_list):
    answer = 1
    for num in num_list:
        answer *= num
    return sum(num_list) if len(num_list) > 10 else answer

문자열의 길이가 11이 넘는 경우 sum()을 통한 합 return, 아닐 경우 for문을 통한 곱 return 

 

10 이하인 경우의 코드 줄여보기 

return sum(num_list) if len(num_list) > 10 else answer *num_list

return sum(num_list) if len(num_list) > 10 else 1* [*num_list]

모두 리스트를 그대로 출력함

 

print('*'.join(str(*[num_list]))) #[*2*,* *3*,* *4*,* *5*]

join에서 언패킹을 하는데 *[num_list]로 또 풀면서 전혀 예상 못한 출력 발생 

 

print('*'.join([str(num) for num in num_list])) #2*3*4*5
print(int('*'.join([str(num) for num in num_list]))) #ValueError

문자열을 내가볼 때는 계산이 가능한 형태로 만들었지만, int로 형변환을 했을 때 실제로 계산이 실행되지 않음 

 

구글링을 통한 eval() 사용

def solution(num_list):
    return sum(num_list) if len(num_list) > 10 else eval('*'.join([str(num) for num in num_list]))

eval()로 감싸게 되면 컴퓨터가 해석 가능한 수식이 문자열로 존재할 때 그 수식을 실행해 준다. 

 해결 방법

def solution(num_list):
    return sum(num_list) if len(num_list) > 10 else eval('*'.join([str(num) for num in num_list]))

코드의 길이는 줄었지만, eval() 함수가 문자열을 수식으로 변환하면서 다양한 경우를 포함하고 그 다양한 경우에 내가 상정하지 않은 상황까지 포함되어 보안상 이슈가 생긴다. 

 

GPT의 선택

def solution(num_list):
    answer = 1
    for num in num_list:
        answer *= num
    return sum(num_list) if len(num_list) > 10 else answer

 

 알게 된 점

eval() 함수를 알게 됐다. 

eval()은 문자열로 수식을 실행하기 때문에 내가 의도치 않은 상황에서 코드가 실행되면서 보안에 이슈가 생길 수 있음을 알게 됐다.

 

1. 팀원과의 코드리뷰 - 직사각형 별 찍기

 문제점

문제 설명
이 문제에는 표준 입력으로 두 개의 정수 n과 m이 주어집니다.
별(*) 문자를 이용해 가로의 길이가 n, 세로의 길이가 m인 직사각형 형태를 출력해보세요.

제한 조건
n과 m은 각각 1000 이하인 자연수입니다.

 시도해 본 것들

for문 사용하기 

a, b = map(int, input().strip().split(' '))
for _ in range(b):
    print('*'*a)

먼저 생각난 for문을 이용해서 푼 풀이 

 

List Comprehension을 이용한 풀이

a, b = map(int, input().split())
print(* ['*' * a for _ in range(b)],sep='\n')

최근에 알게 된 List Comprehension과 언패킹을 동시에 사용했다.

'*' * a를 for _ in range(b)를 통해서 b만큼 반복한 리스트 생성

리스트를 *(언패킹) 하면서 , sep='\n'을 통해서 리스트의 원소가 바뀔 때마다 띄어쓰기 대신 \n을 통한 개행

 

좋다고 생각한 팀원의 코드 

a, b = map(int, input().strip().split(' '))
print((a*'*'+'\n') * b)

for문이 없으면서 코드의 길이도 짧은 코드다.

'*' * a이 끝나면  \n을 넣어서 개행하고 *b로 여러 개를 생성 

 

 해결 방법

# strip() = 문자열의 시작과 끝에서 ()안에 있는 문자 제거, 없으면 공백 제거 
# split() == split(' ') 명시적으로 표시 안해도 빈값이면 공백 제거
a, b = map(int, input().split())
print(* ['*' * a for _ in range(b)],sep='\n')

코드를 이렇게 바꿨는데 GPT에서 코드의 추천도를 물어봤는데 좋은 코드는 아니라고 했다.

 

GPT의 선택 

a, b = map(int, input().strip().split(' '))
for _ in range(b):
    print('*'*a)

 알게 된 점

a, b = map(int, input().strip().split(' '))
print((a*'*'+'\n') * b)

이 코드도 for문을 사용하지는 않았지만, 구조가 for문을 사용한 것과 동일해서 시간복잡도가 다른 코드들과 일치했다.

 

1. 팀원과의 코드리뷰 - 수박수박수박수박수박수?

 문제점

문제 설명
길이가 n이고, "수박수박수박수...."와 같은 패턴을 유지하는 문자열을 리턴하는 함수, 
solution을 완성하세요. 예를들어 n이 4이면 "수박수박"을 리턴하고 3이라면 "수박수"를 리턴하면 됩니다.

제한 조건
n은 길이 10,000이하인 자연수입니다.

 시도해 본 것들

for문과 조건문 사용하기

def solution(n):
    # n은 정수
    # return은 n에 따라 수or박
    answer = ''
    
    for i in range(n):
        if i % 2 == 0:
            answer += '수'
        else:
            answer += '박'
    
    return answer

시작이 0부터 일 때 짝수=수, 홀수=박 이므로 if문을 통한 판별과 for문을 사용해 n만큼 반복

 

삼항 연산자를 통해 리팩토링 

def solution(n):
	answer = ''
    for i in range(n):
        answer += '수' if i % 2 == 0 else '박'
    return answer

로직 자체는 같지만 코드가 간결해짐

 

List Comprehension 사용 

def solution(n):
    # '수' if i % 2 == 0 else '박'이런 조건을 가진 i를 for i in range(n)에서 리스트로 만들기 
    return ''.join(['수' if i % 2 == 0 else '박' for i in range(n)])

아직 List comprehension에 먼저 조건을 선언하고 그 후 for문을 사용하는 방식이 익숙하지 않다.

기존에 사용하던 방법은 for문의 안에서 if문을 사용하면서 값을 찾는데 이건 if문으로 조건을 먼저 설정하고 for문을 사용한다.

 

좋다고 생각한 팀원의 코드 

def solution(n):
    answer = ''
    # water_melon="수박"
    if n%2==0:
        # answer+=water_melon*(n//2)
        answer+="수박"*(n//2)
    else:
        # answer=water_melon*(n//2)+water_melon[0]
        answer+="수박"*(n//2)+"수"
    return answer

 

def solution(n):
    # 짝수일 경우
    if n%2 == 0:
        return '수박'*(n//2)
    # 홀수일 경우
    else:
        return '수'+'박수'*(n//2)

두 코드 모두 반복문 없이 바로 결과가 나오는 코드다. 

 

팀원의 코드 리팩토링

def solution(n):
    return "수박"*(n//2) if n%2==0 else "수박"*(n//2)+"수"

삼항 연산자를 사용해 for문 없이 사용 가능한 코드가 완성됐다. 내가 쓴 코드보다 무슨 뜻을 의미하는지 알기 쉬운 것 같다. 

 해결 방법

GPT의 선택

def solution(n): 
    return ''.join(['수' if i % 2 == 0 else '박' for i in range(n)])

for문이 List Comprehension 내부에 존재하지만 CPython 인터프리터를 사용해 속도가 빠르다고 한다. 

 

 알게 된 점

List Comprehension 내부에서 실행되는 for문은 CPython 인터프리터를 통해서 빠르게 처리된다고 한다. 그러면 단순히 숏코딩이 아니라 시간복잡도의 개선에도 영향이 있기는 하다.

반복문이 아니어도 *를 사용하면 시간복잡도가 비슷해진다는 것을 알았다.