Работа со строками, обработка статистических данных

Моя задача выглядит следующим образом:

Даны результаты забегов в формате "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
→ Ссылка
Автор решения: MiniMax

Так как речь идёт о временных интервалах, я решил использовать модули для работы со временем.

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
→ Ссылка