[프로그래머스 Lv2. 메뉴 리뉴얼 - 파이썬] extend, append 차이, Combinations, Counter 내장함수
코딩테스트 연습 - 메뉴 리뉴얼
레스토랑을 운영하던 스카피는 코로나19로 인한 불경기를 극복하고자 메뉴를 새로 구성하려고 고민하고 있습니다. 기존에는 단품으로만 제공하던 메뉴를 조합해서 코스요리 형태로 재구성해서
programmers.co.kr
처음 짠 코드 (틀린 코드)
문제를 푼 시점에서 생각해보니, 문제를 제대로 이해하지 않고 짜면서 접근을 바꾸려다보니 시작부터 틀어졌다.
course 개수마다 가장 많은 것들을 answer로 내놓아야 한다는 점을 간과하고, 처음엔 모든 조합을 생성해서 table이라는 딕셔너리에 넣고, 개수가 많은 것들을 컷하면 되는 간단한 문제라고 생각했었다.
그래서 모든 가능한 경우를 table ={} 에 넣고 course 개수로 정렬하고, 전체 조합이 다 있는 딕셔너리 안에서 필터링을 하려다보니 점점 복잡해져 갔다.
그래도 문제를 해결하려고 노력하면서 combinations의 개념과 extend, append의 차이를 알게 되었다.
또 filter, sorted, lambda의 사용법도 다시 한번 익히게 되었으니 완전 삽질은 아니었다고 생각해야겠다.
from itertools import combinations
def solution(orders, course):
answer = []
table = {} # {'메뉴': 횟수}
# 가능한 모든 조합 생성해서 table에 넣기
for order in orders:
combi = []
order = sorted(order) # 순서 다른거 확인하려면 -> 알파벳으로 정렬
for i in course:
combi.extend([''.join(x) for x in combinations(order, i)])
for com in combi:
if table.get(com) == None:
table[com] = 1
else:
table[com] += 1
filter_tab = dict(filter(lambda x: x[1]>=2, table.items()))
sort_tab = dict(sorted(filter_tab.items(), reverse=True, key=lambda x: x[1]))
print(sort_tab)
# 동일 value 값 중에서 key의 개수가 가장 많은 것들 리턴
for c in course:
key_dict = list(dict(filter(lambda x: x[1] == c, sort_tab.items())).keys())
max_count = 0
for a in key_dict:
if len(a) > max_count:
max_count = len(a)
final_dict = list(filter(lambda x: len(x) == max_count, key_dict))
answer.extend(final_dict)
return sorted(answer)
위 코드로 짜면 주어진 테스트 케이스 3문제는 모두 통과하지만 아래와 같은 테스트 케이스는 틀려버린다.
입력값 〉 | ["ABCD", "ABCD", "ABCD"], [2, 3, 4] |
기댓값 〉 | ["AB", "ABC", "ABCD", "ABD", "AC", "ACD", "AD", "BC", "BCD", "BD", "CD"] |
실행 결과 〉 | 실행한 결괏값 ["ABCD"]이 기댓값 ["AB","ABC","ABCD","ABD","AC","ACD","AD","BC","BCD","BD","CD"]과 다릅니다. |
출력 〉 | {'AB': 3, 'AC': 3, 'AD': 3, 'BC': 3, 'BD': 3, 'CD': 3, 'ABC': 3, 'ABD': 3, 'ACD': 3, 'BCD': 3, 'ABCD': 3} |
다시 짠 코드
def solution(orders, course):
answer = []
for c in course:
combi_arr1 = []
combi_arr = []
for order in orders:
for combi in combinations(order, c):
combi_arr1.append(''.join(sorted(combi)))
# for order in orders:
# order = sorted(order)
# combi = combinations(order, c)
# combi_arr.extend(''.join(x) for x in combi)
counter = Counter(combi_arr1)
if len(counter) != 0 and max(counter.values()) >= 2:
for x in counter:
if counter[x] == max(counter.values()):
answer.append(x)
return sorted(answer)
주석 부분과 combi_arr가 두 개 있는 것은 똑같이 동작하는 코드이다. (extend와 append 차이를 볼 수 있는 부분)
extend 와 append의 주요 차이점을 쉽게 요약하자면,
x = ['a', 'b', 'c']
y = ['d', 'e']
z = [['f', 'g']]
x.append(y) : ['a', 'b', 'c', ['d', 'e']]
x.extend(y) : ['a', 'b', 'c', 'd', 'e']
x.append(z) : ['a', 'b', 'c', [['f', 'g']]]
x.extend(y) : ['a', 'b', 'c', ['f', 'g']]
list에 list를 넣을 때, extend 는 [ ] 한 겹을 벗겨서 들어가고, append는 [ ] 형태의 list 통째로 들어간다고 생각하면 편하다.
그리고 구글링을 통해 새로 안 Counter라는 내장함수.
Counter(배열) : 각 원소의 등장 횟수를 dictionary 형태로 반환한다.