Работа со строками, обработка статистических данных
Моя задача выглядит следующим образом:
Даны результаты забегов в формате
"h|m|s, h|m|s, h|m|s"(h – часы, m – минуты, s – секунды).
Написать функциюstat, которая возвращает строку в формате:
"Range: hh|mm|ss Average: hh|mm|ss"
(range– разница между максимальным и минимальным значением,average– среднее значение)
Пример:stat("01|15|59, 1|47|6, 01|17|20, 1|32|34, 2|3|17")==>"Range: 00|47|18 Average: 01|35|15"
import traceback
def stat(s):
# Тело функции
return "
# Тесты
try:
assert stat("01|15|59, 1|47|16,
01|17|20, 1|32|34,
2|17|17") == "Range: 01|01|18
Average: 01|38|05"
assert stat("02|15|59, 2|47|16,
02|17|20, 2|32|34,
2|17|17, 2|22|00,
2|31|41") == "Range: 00|31|17
Average: 02|26|18"
except AssertionError:
print("TEST ERROR")
traceback.print_exc()
else:
print("TEST PASSED")
Я пробую решить эту задачу так:
hs = ['02',2,'02',2,2,2,2]
ms = [15,47,17,32,17,22,31]
ss = [59,16,20,34,17,'00',41]
tmp = []
avg = []
rng = []
def myStat(x,y,y1):
IntX = []
for i in range(len(x)):
IntX.append(int(x[i]))
print("Массив целых на входе:%s\n" % IntX)
M = max(IntX)
m = min(IntX)
ran0 = M-m
avg0 = round( sum(IntX)/len(IntX) )
y.append(ran0)
y1.append(avg0)
return y,y1
print(myStat(hs,tmp,avg))
print(myStat(ms,tmp,avg))
print(myStat(ss,tmp,avg))
На данный момент без форматирования, так как тренировался с преобразованием строк в массив целых и с функцией format( ). Я не понимаю от чего в этой строке такой вывод, ведь по условию задачи Range - это разница между минимальным и максимальным, а Average - это среднее, хочу разобраться где ошибка, в моих вычилсениях или в описании задания ? И возможно ли заменить нагромождения на анонимную фукцию ?
assert stat("02|15|59, 2|47|16,
02|17|20, 2|32|34,
2|17|17, 2|22|00,
2|31|41") == "Range: 00|31|17
Average: 02|26|18"
Ответы (2 шт):
Дело в том, что вы округляете значение часов при делении, т.е. бесследно забываете о том, что там был остаток, хотя его следует спускать на ранг ниже (если есть остаток от деления часов - его следует переводить в минуты, если остаток от деления минут - в секунды)
Мой вариант решения вашей задачи. Возможно, натолкнёт вас на мысли к исправлению:
res = "01|15|59, 1|47|6, \
01|17|20, 1|32|34, \
2|3|17"
def myStat(res):
results = [[int(i) for i in r.strip().split('|')] for r in res.split(',')] # привели данные к списку кортежей [(h, m, s), (h, m, s), ...]
results = [r[0]*3600 + r[1]*60 + r[2] for r in results] # перевели все результаты в секунды
average = sum(results) / len(results) # посчитали средний результат в секундах
average = average//3600, average%3600//60, average%60 # перевели в кортеж (h, m, s). Если значение секунд нужно целым, Range%60 заменяем на round(Range%60)
average = '|'.join(str(e) for e in average) # если нужно - привели к виду 'h|m|s'. Если не нужно - строку убрать/закомментировать
Range = max(results) - min(results) # посчитали разницу в секундах
Range = Range//3600, Range%3600//60, Range%60 # перевели в кортеж (h, m, s). Если значение секунд нужно целым, Range%60 заменяем на round(Range%60)
Range = '|'.join(str(e) for e in Range) # если нужно - привели к виду 'h|m|s'. Если не нужно - строку убрать/закомментировать
return Range, average
print('Range: {} Average: {}'.format(*myStat(res)))
Алтернативный вариант с результатом сразу в виде строки:
...
return 'Range: {} Average: {}'.format(Range, average)
print(myStat(res))
Результат:
Range: 0|47|18 Average: 1.0|35.0|15.199999999999818
Так как речь идёт о временных интервалах, я решил использовать модули для работы со временем.
from datetime import timedelta
from time import gmtime, strftime, strptime
def stat(s):
def format_tm_delta(tm_delta):
return strftime("%H|%M|%S", gmtime(tm_delta.seconds))
tm_lst = []
for tm in s.split(', '):
h, m, s = map(int, tm.split('|'))
tm_lst.append(timedelta(hours=h, minutes=m, seconds=s))
rng = format_tm_delta(max(tm_lst) - min(tm_lst))
avg = format_tm_delta(sum(tm_lst, timedelta()) / len(tm_lst))
return f"Range: {rng} Average: {avg}"
Тестирование
print(stat("01|15|59, 1|47|16, 01|17|20, 1|32|34, 2|17|17"))
print(stat("02|15|59, 2|47|16, 02|17|20, 2|32|34, 2|17|17, 2|22|00, 2|31|41"))
Output
Range: 01|01|18 Average: 01|38|05
Range: 00|31|17 Average: 02|26|18