목표
- 기존에 문제를 푸는데만 집중해서 풀었던 문제들을 클린 코드, 객체 지향 방식으로 리팩토링
- 완벽한 효율보다는 다양한 스타일로 작성
코테 문제) https://school.programmers.co.kr/learn/courses/30/lessons/131127
정현이가 원하는 제품을 나타내는 문자열 배열 want와 정현이가 원하는 제품의 수량을 나타내는 정수 배열 number, XYZ 마트에서 할인하는 제품을 나타내는 문자열 배열 discount가 주어졌을 때, 회원등록시 정현이가 원하는 제품을 모두 할인 받을 수 있는 회원등록 날짜의 총 일수를 return 하는 solution 함수를 완성하시오. 가능한 날이 없으면 0을 return 합니다.
제한사항
from collections import defaultdict
DAY_RANGE = 10
def check_list(want_list, dc_list):
for want_item, cnt in want_list.items():
if want_item not in dc_list:
return False
elif dc_list[want_item] < cnt:
return False
return True
def solution(want, number, discount):
answer = 0
dc_list = defaultdict(int)
want_list = {item:cnt for item, cnt in zip(want, number)}
for item in discount[:DAY_RANGE]:
dc_list[item] += 1
loop_cnt = len(discount) - DAY_RANGE + 1
for day in range(loop_cnt):
if check_list(want_list, dc_list):
answer += 1
if day + DAY_RANGE < len(discount):
dc_list[discount[day]] -= 1
dc_list[discount[day + DAY_RANGE]] += 1
return answer
from collections import Counter
class Mart:
def __init__(self, discount: list) -> None:
self.day: int = 0
self.day_range: int = 10
self.discounts: list = discount
self.discounts_counter: Counter = Counter(discount[:self.day_range])
def shift_discounts_to_next_day(self) -> None:
if self.is_last_day():
return
self._remove_old_discount()
self._add_new_discount()
self.day += 1
def is_last_day(self) -> bool:
return self.day + self.day_range == len(self.discounts)
def _remove_old_discount(self) -> None:
item_to_remove = self.discounts[self.day]
self.discounts_counter[item_to_remove] -= 1
if self.discounts_counter[item_to_remove] == 0:
del self.discounts_counter[item_to_remove]
def _add_new_discount(self) -> None:
item_to_add = self.discounts[self.day + self.day_range]
self.discounts_counter[item_to_add] += 1
@property
def discount_period(self) -> int:
return len(self.discounts) - self.day_range + 1
class Visitor:
def __init__(self, want: list, number: list) -> None:
self.buying_counter: Counter = Counter(dict(zip(want, number)))
def can_purchase_with_discount(self, discounts_counter: Counter) -> bool:
for item, required_count in self.buying_counter.items():
if discounts_counter[item] < required_count:
return False
return True
def solution(want: list, number: list, discount: list) -> int:
answer: int = 0
visitor: Visitor = Visitor(want, number)
mart: Mart = Mart(discount)
for _ in range(mart.discount_period):
if visitor.can_purchase_with_discount(mart.discounts_counter):
answer += 1
mart.shift_discounts_to_next_day()
return answer
개선점
defaultdict
대신 Counter
사용으로 코드 간소화Mart
, Visitor
객체를 통해 역할 분리