기술스택을 쌓아보자/Python
[Codewars 6kyu / Python]- datetime 패키지로 날짜 빼고 시간만 처리하기/시간 연산하기
소리331
2023. 4. 16. 13:08
반응형
문제
여러분은 한 기업의 컴퓨팅 전문가입니다. 특정 시간들에 대한 인풋값을 입력하면 해당 시간의 range, avg, median 값을 출력해야 합니다. 예상되는 input과 output의 형태는 아래와 같습니다.
"01|15|59, 1|47|6, 01|17|20, 1|32|34, 2|3|17"
=> "Range: 00|47|18 Average: 01|35|15 Median: 01|32|34"
- 이 문제는 날짜를 다룰 필요가 없습니다.
- 시간은 60진수 바탕이기 때문에 일반적인 숫자처럼 다루기 보다는 time 형태로 변환하여 연산해야합니다.
[삼천포] datetime 패키지로 시간만 처리하기
보통 datetime 을 쓸 때, datetime.datetime 혹은 datetime.date 패키지를 사용한다. 여기서 datetime.datetime 과 datetime.date의 차이는, date는 시간이 없고 datetime 은 시간 처리가 있다는 것이다. 그러나 datetime은 시간만 단독으로 쓰지 못한다. 때문에 datetime.time을 사용한다.
from datetime import datetime, date, time
datetime(2023, 4, 15, 2, 3, 1) #연월일시분초
date(2023, 4, 15) #연월일
time(2, 3, 1) #시분초
그런데 이렇게 날짜, 시간객체로 변환하면 우리가 원하는 평균, 빼기 등의 연산이 되지 않는다. 때문에 사실 이 문제에서는 time 보다는 timedelta로 변환하는게 적합해보인다.
from datetime import time
time(2,3,3) - time(2,3,1)
# 연산이 되지 않는다.
TypeError Traceback (most recent call last)
<ipython-input-13-7a269ee28cf9> in <cell line: 1>()
----> 1 time(2,3,3) - time(2,3,1)
TypeError: unsupported operand type(s) for -: 'datetime.time' and 'datetime.time
시간 객체 연산하기(time operation by timedelta)
때문에 위의 문제를 풀기 위해, 나는 모든 input 값을 timedelta로 변환했다. 이후에는 아래와 같은 연산이 가능해진다.
timedelta(hours=2,minutes=3,seconds=3) - timedelta(hours=2,minutes=3,seconds=1)
# 결과
datetime.timedelta(seconds=2)
공홈에서는 아래처럼 한다
from datetime import timedelta
>>> year = timedelta(days=365)
>>> ten_years = 10 * year
>>> ten_years
datetime.timedelta(days=3650)
>>> ten_years.days // 365
10
>>> nine_years = ten_years - year
>>> nine_years
datetime.timedelta(days=3285)
>>> three_years = nine_years // 3
>>> three_years, three_years.days // 365
(datetime.timedelta(days=1095), 3)
문제 풀이
나는 아래와 같이 풀었다.
from datetime import time, timedelta, date
def stat(strg):
if strg == "":
return strg
inps = []
for t in [
t.split("|") for t in strg.replace(" ", "").split(",")
]:
t = list(map(int, t))
inps.append(timedelta(hours=t[0], minutes=t[1], seconds=t[2]))
inps = sorted(inps)
average = cal_avg(inps)
range_ = cal_range(inps)
mid = cal_mid(inps)
return f"Range: {range_} Average: {average} Median: {mid}"
def trim(i):
return str(i).zfill(2)
def time_format(td):
r = td if type(td) in [int, float] else td.seconds
h, m, s = int(r//3600), int(r%3600//60), int(r%60)
print(h,m,s)
return f"{trim(h)}|{trim(m)}|{trim(s)}"
def cal_avg(inps):
total_seconds = sum(list(map(lambda x: x.seconds, inps)))
mean_seconds = total_seconds/len(inps)
return time_format(mean_seconds)
def cal_range(inps):
min_, max_ = inps[0], inps[-1]
r = max_ - min_
return time_format(r)
def cal_mid(inps):
if len(inps)%2==0:
idx=len(inps)//2
mid = (inps[idx-1] + inps[idx])/2
else:
idx=len(inps)//2+1
mid = inps[idx-1]
return time_format(mid)
Codewars는 다 풀고 나면 타인의 풀이도 공유되는데, 아래처럼 time 객체를 사용하지 않고 푸는 케이스도 있었다.
from statistics import median, mean
def stat(s):
if not s: return ''
t = [itime(w) for w in s.split(',')]
return 'Range: {} Average: {} Median: {}'.format(stime(max(t) - min(t)), stime(int(mean(t))), stime(int(median(t))))
def itime(w):
return sum([int(c) * 60**i for i, c in enumerate(w.split('|')[::-1])])
def stime(n):
return '{:02d}|{:02d}|{:02d}'.format(n // 3600, (n % 3600) // 60, n % 60)
참조링크
반응형