목록 보기
날짜 구간에 값을 매핑하는 방법 (그리고 RangeKeyDict)
기타

날짜 구간에 값을 매핑하는 방법 (그리고 RangeKeyDict)

8퍼센트
8퍼센트
2019년 12월 16일

일정한 날짜 구간에 값을 매핑하는 방법을 알아봅시다. 한 줄 요약 날짜 구간에 값을 매핑할 때 RangeKeyDict를 이용하면 깔끔합니다. 자세히 특정 일자에 따라 값을 다르게 설정해야 하는 경우가 자주 있습니다. 예를 들어, 회사의 포인트 적립 정책이 2020년 1월 1일부터는 1 퍼센트, 2020년 2월 2일부터는 2 퍼센트, 2020년 8월 8일부터는 8퍼센트라고 합시다. 이것은 if 문을 이용해 간단히 코드로 옮길 수 있습니다. from datetime import date from decimal import Decimal

def date_to_point_rate(base_date): if base_date < date(2020, 1, 1): return None if base_date < date(2020, 2, 2): return Decimal('0.01') if base_date < date(2020, 8, 8): return Decimal('0.02') return Decimal('0.08')

assert date_to_point_rate(date(2019, 12, 31)) is None assert date_to_point_rate(date(2020, 1, 1)) == Decimal('0.01') assert date_to_point_rate(date(2020, 2, 2)) == Decimal('0.02') assert date_to_point_rate(date(2020, 8, 8)) == Decimal('0.08') 하지만 이런 방식은 날짜 구간이 변경될 때마다 비교식을 수정해야 하는 부담이 있습니다. 작성한 코드도 한눈에 쉽게 들어오지 않습니다. 자세히 보지 않으면 2019년 8월 8일의 포인트 적립율이 2퍼센트인지 8퍼센트인지 헷갈릴 수 있다고 생각합니다. 더 좋은 방법 날짜 구간에 값을 매핑해야 하는 경우가 자주 있어서 더 좋은 방법을 생각해 보았습니다. 날짜와 값을 쌍으로 지정해 두고 그 안에서 날짜를 맞추면 어떨까요? # 주의: 적용 날짜를 내림차순으로 나열해야 한다. applying_date_to_point_rate_pairs = ( (date(2020, 8, 8), Decimal('0.08')), (date(2020, 2, 2), Decimal('0.02')), (date(2020, 1, 1), Decimal('0.01')), (date.min, None), )

def date_to_point_rate_v2(base_date): for applying_date, point_rate in applying_date_to_point_rate_pairs: if applying_date <= base_date: return point_rate

assert date_to_point_rate_v2(date(2019, 12, 31)) is None assert date_to_point_rate_v2(date(2020, 1, 1)) == Decimal('0.01') assert date_to_point_rate_v2(date(2020, 2, 2)) == Decimal('0.02') assert date_to_point_rate_v2(date(2020, 8, 8)) == Decimal('0.08') 이렇게 하면 날짜 매핑을 로직 대신 값으로 설정할 수 있습니다. 이제 날짜 구간을 변경할 때 applying_date_to_point_rate_pairs에서 날짜와 값 쌍을 수정하면 됩니다. 하지만 여전히 단점이 있습니다. 적용 날짜를 내림차순으로 입력해야 한다는 점이 자연스럽지 않은 것 같습니다.(일반적으로 오름차순이 기본이므로) 그리고 date_to_point_rate_v2 함수를 이해하기가 약간은 어려운 것 같습니다. 이 코드를 보고 직장 동료 김남홍 님이 좋은 방법을 귀뜸해 줬습니다. “RangeKeyDict 한 번 써봐!” RangeKeyDict RangeKeyDict는 파이썬에 이런 게 있으면 좋겠다고 한 번쯤 생각했던 겁니다. 값의 범위(range)를 사전(dict)의 키로 사용할 수 있는 매핑 컬렉션입니다. RangeKeyDict를 사용하려면 range-key-dict 패키지를 설치해야 합니다. pip install range-key-dict 이제 range_key_dict.RangeKeyDict를 임포트하여 RangeKeyDict(((start, end): value))와 같은 형태로 매핑을 작성할 수 있습니다. 포인트 정책을 RangeKeyDict로 수정해 봅시다. from range_key_dict import RangeKeyDict

applying_date_to_point_rate_mapping = RangeKeyDict(( (date.min, date(2020, 1, 1)): None, (date(2020, 1, 1), date(2020, 2, 2)): Decimal('0.01'), (date(2020, 2, 2), date(2020, 8, 8)): Decimal('0.02'), (date(2020, 8, 8), date.max): Decimal('0.08'), ))

def date_to_point_rate_v3(base_date): return applying_date_to_point_rate_mapping[base_date]

assert date_to_point_rate_v3(date(2019, 12, 31)) is None assert date_to_point_rate_v3(date(2020, 1, 1)) == Decimal('0.01') assert date_to_point_rate_v3(date(2020, 2, 2)) == Decimal('0.02') assert date_to_point_rate_v3(date(2020, 8, 8)) == Decimal('0.08') 코드가 꽤 직관적입니다. RangeKeyDict는 꼭 날짜가 아니더라도 어떤 범위에 값을 매핑할 때 편리하게 사용할 수 있습니다. 자주 바뀌는 법령이나 정책을 적용할 때 RangeKeyDict를 활용해보시면 좋을 것입니다.

댓글 0

댓글을 작성하려면 로그인이 필요합니다.

댓글을 불러오는 중...