Среднее timedelta в списке
Я хочу рассчитать среднее значение времени между датами в списке.
Хотя следующее работает хорошо, мне интересно, есть ли более умный способ?
delta = lambda last, next: (next - last).seconds + (next - last).days * 86400
total = sum(delta(items[i-1], items[i]) for i in range(1, len(items)))
average = total / (len(items) - 1)
Ответы
Ответ 1
Btw, если у вас есть список timedeltas или datetimes, почему вы даже делаете какую-либо математику самостоятельно?
datetimes = [ ... ]
# subtracting datetimes gives timedeltas
timedeltas = [datetimes[i-1]-datetimes[i] for i in range(1, len(datetimes))]
# giving datetime.timedelta(0) as the start value makes sum work on tds
average_timedelta = sum(timedeltas, datetime.timedelta(0)) / len(timedeltas)
Ответ 2
Попробуйте следующее:
from itertools import izip
def average(items):
total = sum((next - last).seconds + (next - last).days * 86400
for next, last in izip(items[1:], items))
return total / (len(items) - 1)
По-моему, делать это так читаемо. Комментарий для менее математически склонных читателей вашего кода может помочь объяснить, как вы вычисляете каждую дельту. Для того, что это стоит, одно выражение генератора имеет наименьшее (и я думаю наименее медленное) указание инструкций по чему-либо, на что я смотрел.
# The way in your question compiles to....
3 0 LOAD_CONST 1 (<code object <lambda> at 0xb7760ec0, file
"scratch.py", line 3>)
3 MAKE_FUNCTION 0
6 STORE_DEREF 1 (delta)
4 9 LOAD_GLOBAL 0 (sum)
12 LOAD_CLOSURE 0 (items)
15 LOAD_CLOSURE 1 (delta)
18 BUILD_TUPLE 2
21 LOAD_CONST 2 (<code object <genexpr> at 0xb77c0a40, file "scratch.py", line 4>)
24 MAKE_CLOSURE 0
27 LOAD_GLOBAL 1 (range)
30 LOAD_CONST 3 (1)
33 LOAD_GLOBAL 2 (len)
36 LOAD_DEREF 0 (items)
39 CALL_FUNCTION 1
42 CALL_FUNCTION 2
45 GET_ITER
46 CALL_FUNCTION 1
49 CALL_FUNCTION 1
52 STORE_FAST 1 (total)
5 55 LOAD_FAST 1 (total)
58 LOAD_GLOBAL 2 (len)
61 LOAD_DEREF 0 (items)
64 CALL_FUNCTION 1
67 LOAD_CONST 3 (1)
70 BINARY_SUBTRACT
71 BINARY_DIVIDE
72 STORE_FAST 2 (average)
75 LOAD_CONST 0 (None)
78 RETURN_VALUE
None
#
#doing it with just one generator expression and itertools...
4 0 LOAD_GLOBAL 0 (sum)
3 LOAD_CONST 1 (<code object <genexpr> at 0xb777eec0, file "scratch.py", line 4>)
6 MAKE_FUNCTION 0
5 9 LOAD_GLOBAL 1 (izip)
12 LOAD_FAST 0 (items)
15 LOAD_CONST 2 (1)
18 SLICE+1
19 LOAD_FAST 0 (items)
22 CALL_FUNCTION 2
25 GET_ITER
26 CALL_FUNCTION 1
29 CALL_FUNCTION 1
32 STORE_FAST 1 (total)
6 35 LOAD_FAST 1 (total)
38 LOAD_GLOBAL 2 (len)
41 LOAD_FAST 0 (items)
44 CALL_FUNCTION 1
47 LOAD_CONST 2 (1)
50 BINARY_SUBTRACT
51 BINARY_DIVIDE
52 RETURN_VALUE
None
В частности, сброс лямбда позволяет избежать замыкания, создания кортежа и загрузки двух затворов. Пять функций вызываются в любом случае. Конечно, такая озабоченность работой - это нечто вроде смешного, но приятно знать, что происходит под капотом. Самое главное - это читаемость, и я думаю, что это так же оценивается на этом.