Среднее 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

В частности, сброс лямбда позволяет избежать замыкания, создания кортежа и загрузки двух затворов. Пять функций вызываются в любом случае. Конечно, такая озабоченность работой - это нечто вроде смешного, но приятно знать, что происходит под капотом. Самое главное - это читаемость, и я думаю, что это так же оценивается на этом.