[TIL] 230321 [알고리즘] [Python] Level1.모의고사 - 코드 축약
TIL 학습목표
- 알고리즘 문제를 이해하고 사고의 접근 방식을 설계할 수 있다.
- 코드 길이를 줄이는데에 용이한 python 함수들을 안다.
- python 함수들을 활용해, 작성한 코드의 길이를 효율적으로 축약할 수 있다.
1) 문제점 (Problem)
프로그래머스 Level1.모의고사 를 풀어보았다.
처음으로 푼 알고리즘인 만큼 어떻게 접근했는지 사고 방식과 풀이과정을 되짚어보자.
그리고 문법을 배우기 전 작성한 코드라 난잡함이 있다.
완성된 코드를 python문법 강의를 통해 배운 코드들로 축약해보도록 하자.
문제 설명
수포자는 수학을 포기한 사람의 준말입니다. 수포자 삼인방은 모의고사에 수학 문제를 전부 찍으려 합니다.
수포자는 1번 문제부터 마지막 문제까지 다음과 같이 찍습니다.
- 1번 수포자가 찍는 방식: 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...
- 2번 수포자가 찍는 방식: 2, 1, 2, 3, 2, 4, 2, 5, 2, 1, 2, 3, 2, 4, 2, 5, ...
- 3번 수포자가 찍는 방식: 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, ...
1번 문제부터 마지막 문제까지의 정답이 순서대로 들은 배열 answers가 주어졌을 때, 가장 많은 문제를 맞힌 사람이 누구인지 배열에 담아 return 하도록 solution 함수를 작성해주세요.
제한 조건
- 시험은 최대 10,000 문제로 구성되어있습니다.
- 문제의 정답은 1, 2, 3, 4, 5중 하나입니다.
- 가장 높은 점수를 받은 사람이 여럿일 경우, return하는 값을 오름차순 정렬해주세요.
입출력 예
answers | return |
[1,2,3,4,5] | [1] |
[1,3,2,4,2] | [1,2,3] |
입출력 예 설명
입출력 예 #1
- 수포자 1은 모든 문제를 맞혔습니다.
- 수포자 2는 모든 문제를 틀렸습니다.
- 수포자 3은 모든 문제를 틀렸습니다.
따라서 가장 문제를 많이 맞힌 사람은 수포자 1입니다.
입출력 예 #2
- 모든 사람이 2문제씩을 맞췄습니다.
2) 시도해본 것들 (Try)
▶문제 접근과 사고의 순서
문제 설명 >1번 수포자 찍는 방식 → 1번 패턴 리스트 [1,2,3,4,5] 5개
문제 설명 >2번 수포자 찍는 방식 → 1번 패턴 리스트 [2,1,2,3,2,4,2,5] 8개
문제 설명 >3번 수포자 찍는 방식 → 1번 패턴 리스트 [3,3,1,1,2,2,4,4,5,5] 10개
문제 설명 >"정답이 순서대로 들은 배열 answers" → 반복문 + 리스트 활용
문제 설명 >"가장 많은 문제를 맞힌 사람" → 합을 구해야한다 + max()함수 활용
문제 설명 >"배열에 담아 return" → 결과값이 리스트로 나와야한다
제한 조건>시험은 최대 10,000 문제로 구성. → 10,000개 초과의 answers가 입력될 경우 구동하지 않도록 설계
제한 조건>문제의 정답은 1, 2, 3, 4, 5중 하나. → 수포자가 찍는 방식에도 1,2,3,4,5 만 있으므로 따로 고려할 부분은 없다
제한 조건>가장 높은 점수를 받은 사람이 여럿일 경우, return하는 값을 오름차순 정렬. → sort() 로 오름차순 정렬하기
▶코드로 구현
이 때, a b c 를 10,000개의 배열로 만든 이유는 10,001개의 answers가 입력 되었을 때
IndexError: list index out of range 가 되어 함수 solution이 작동하지 않도록 하기 위함이다.
def solution(answers):
#수포자 1,2,3을 a,b,c로 표현
a = [1,2,3,4,5]*2000 #10,000개의 배열 만들기 5*2000
b = [2,1,2,3,2,4,2,5]*1250 #10,000개의 배열 만들기 8*1250
c = [3,3,1,1,2,2,4,4,5,5]*1000 #10,000개의 배열 만들기 10*1000
count_a=0 #수포자1의 맞춘 갯수
count_b=0 #수포자2의 맞춘 갯수
count_c=0 #수포자3의 맞춘 갯수
for i, answer in enumerate(answers): #반복문 for 구문. 인덱스(i)로 순차배열 i는 0부터 시작한다
if answer == a[i]: #answers의 요소와 a의 요소를 비교하고, 맞을 경우
count_a += 1 #count_a에 1씩 더해준다
if answer == b[i]:
count_b += 1
if answer == c[i]:
count_c += 1
total=[count_a,count_b,count_c] #수포자1,2,3의 맞춘 개수를 total이라는 리스트로 저장
result=[] #문제에서 원하는 결과를 result 라고 표현
for i in range(0,3): #1,2,3 세 명이니 3번만 반복
if max(total) == total[i]: #공동이든 단독이든, 3명의 결과 중 가장 많이 맞춘경우
result.append(i+1) #수포자 번호에 맞는 번호를 리스트에 추가해라
result.sort() #리스트를 오름차순 정렬해라
return result
▶코드 축약에 용이한 python 함수
◇ if - 삼항연산자
☞ result = (참일 때 값) if (조건) else (거짓일 때 값) *항이 3개!
result = ("짝수" if num%2 == 0 else "홀수") #소괄호 생략가능
#"짝수"라고 해라. 만약 2로 나눈 나머지가 0이라면. 아니면 "홀수"라 해라.
◇for - 축약
☞ b_list = [a*2 for a in a_list]
#Before
a_list = [1, 3, 2, 5, 1, 2]
b_list = []
for a in a_list:
b_list.append(a*2)
print(b_list)
#After
a_list = [1, 3, 2, 5, 1, 2]
b_list = [a*2 for a in a_list] # a_list의 a를 a*2 한 것을 b_list 에 저장해줘
print(b_list)
◇map lambda 식
map ☞ 리스트의 모든 원소 조작 == map(함수,참조할 리스트)
people = [...]
def check_adult(person):
if person['age'] > 20:
return '성인'
else:
return '청소년'
result = map(check_adult, people) #map(함수명, 리스트명) : 리스트 요소를 하나씩 함수에 넣은 결과
print(list(result))
people = [...]
def check_adult(person):
return '성인' if person['age'] > 20 else '청소년' # if 삼항연산자
result = map(check_adult, people)
print(list(result))
lambda ☞ map의 '함수' 부분에 함수를 축약하여 기입 == map(lambda x: (조건문), 참조할 리스트)
#lambda 적용
people = [...]
result = map(lambda x: ('성인' if x['age'] > 20 else '청소년'), people)
#people리스트의 각 원소마다(=lambda x) 조건문(if 삼항연산자)을 실행해줘
print(list(result))
◇filter
☞ 리스트의 모든 원소 중 특정한 것만 출력
result = filter(lambda x: x['age'] > 20, people)
print(list(result))
이제 배운것들을 활용해 코드를 축약해보자.
3) 해결 (Solution)
축약 함수를 적용 못했다. 강해져서 돌아오자.(23.03.21)
for 문 안의 if 문을 축약하는 방법을 아직 찾아내지 못했다.
강해져서 돌아왔다. 축약 함수를 적용했다. (23.03.22)
def solution(answers):
spj1 = [1,2,3,4,5]*2000 #수포자1
spj2 = [2,1,2,3,2,4,2,5]*1250 #수포자2
spj3 = [3,3,1,1,2,2,4,4,5,5]*1000 #수포자3
spj = [spj1,spj2,spj3] #수포자리스트
score=[0,0,0] #수포자 점수 리스트
# 축약 코드 리스트 컴프리헨션
score=[sum(score[j] + 1 for i,answer in enumerate(answers) if answer == spj[j][i]) for j in range(0,3)]
#맞춘 문제수를 score에 리스트로 저장
No_1=[k+1 for k in range(0,3) if max(score) == score[k]]
#맞춘 문제수를 비교하여 최고점의 수포자번호를 No_1에 리스트로 저장
No_1.sort() #No_1 내림차순 정렬
return No_1
변수들을 좀 더 직관적인 이름으로 바꾸었고, 축약함수들을 적용하였다.
그리고 리스트 컴프리헨션 이라는 개념을 배웠다.
◇리스트 컴프리헨션
☞ 패턴이 있는 리스트(list)를 보다 간단하게 작성할 수 있도록 지원
#Before
numbers = []
for n in range(1, 10+1):
numbers.append(n)
#After
#리스트 컴프리헨션
>>> [x for x in range(10)]
4) 알게 된 점 (Learnd)
알고리즘의 사고 순서와, 그것을 코드로 구현하는 법.
구현한 코드를 축약하는 함수와 그 사용법을 배웠다.
추가적으로 컴프리헨션(Comprehension) 개념을 배웠다.
리스트와 딕셔너리 두 가지 모두 있으니 앞으로 알고리즘문제를 풀면서 코드를 축약하는 것과 단순화 하는 것에 적용해보도록 하자.