2012-01-24 13 views
10

Tengo una lista ordenada de datetimes: (con huecos día)lista de Split de datetimes en día

list_of_dts = [ 
       datetime.datetime(2012,1,1,0,0,0), 
       datetime.datetime(2012,1,1,1,0,0), 
       datetime.datetime(2012,1,2,0,0,0), 
       datetime.datetime(2012,1,3,0,0,0), 
       datetime.datetime(2012,1,5,0,0,0), 
       ] 

Y me gustaría dividir en una lista para cada día:

result = [ 
      [datetime.datetime(2012,1,1,0,0,0), datetime.datetime(2012,1,1,1,0,0)], 
      [datetime.datetime(2012,1,2,0,0,0)], 
      [datetime.datetime(2012,1,3,0,0,0)], 
      [], # Empty list for no datetimes on day 
      [datetime.datetime(2012,1,5,0,0,0)] 
     ] 

Algorítmicamente, debería ser posible lograr al menos O (n).

Tal vez algo así como los siguientes: (esto obviamente no maneja Ha faltado, y deja caer el último dt, pero es un comienzo)

def dt_to_d(list_of_dts): 
    result = [] 
    start_dt = list_of_dts[0] 
    day = [start_dt] 
    for i, dt in enumerate(list_of_dts[1:]): 
     previous = start_dt if i == 0 else list_of_dts[i-1] 
     if dt.day > previous.day or dt.month > previous.month or dt.year > previous.year: 
      # split to new sub-list 
      result.append(day) 
      day = [] 
      # Loop for each day gap? 
     day.append(dt) 
    return result 

Pensamientos?

+1

usar un diccionario de listas con datetime_value .date() como claves. –

Respuesta

12

La manera más fácil de ir es utilizar dict.setdefault a las entradas de grupo que caen en el mismo día y luego bucle sobre el día bajo al más alto:

>>> import datetime 
>>> list_of_dts = [ 
       datetime.datetime(2012,1,1,0,0,0), 
       datetime.datetime(2012,1,1,1,0,0), 
       datetime.datetime(2012,1,2,0,0,0), 
       datetime.datetime(2012,1,3,0,0,0), 
       datetime.datetime(2012,1,5,0,0,0), 
       ] 

>>> days = {} 
>>> for dt in list_of_dts: 
     days.setdefault(dt.toordinal(), []).append(dt) 

>>> [days.get(day, []) for day in range(min(days), max(days)+1)] 
[[datetime.datetime(2012, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 1, 0)], 
[datetime.datetime(2012, 1, 2, 0, 0)], 
[datetime.datetime(2012, 1, 3, 0, 0)], 
[], 
[datetime.datetime(2012, 1, 5, 0, 0)]] 

Otro enfoque para la fabricación de estas agrupaciones es itertools.groupby. Está diseñado para este tipo de trabajo, pero no proporciona una manera de rellenar una lista vacía de días que faltan:

>>> import itertools 
>>> [list(group) for k, group in itertools.groupby(list_of_dts, 
                key=datetime.datetime.toordinal)] 
[[datetime.datetime(2012, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 1, 0)], 
[datetime.datetime(2012, 1, 2, 0, 0)], 
[datetime.datetime(2012, 1, 3, 0, 0)], 
[datetime.datetime(2012, 1, 5, 0, 0)]] 
+1

setdefault y toordinal son buenas mejoras sobre mi respuesta. :-) –

+2

Incluso más simple que 'setdefault' puede ser' defaultdict' (de 'collections'). – Amber

+0

Hermosa - gracias! Puedo generar mi lista de 'días' al mismo tiempo que mi' list_of_dts', por lo que será súper eficiente. –

4

Puede utilizar itertools.groupby para manejar fácilmente este tipo de problemas:

import datetime 
import itertools 

list_of_dts = [ 
     datetime.datetime(2012,1,1,0,0,0), 
     datetime.datetime(2012,1,1,1,0,0), 
     datetime.datetime(2012,1,2,0,0,0), 
     datetime.datetime(2012,1,3,0,0,0), 
     datetime.datetime(2012,1,5,0,0,0), 
     ] 

print [list(g) for k, g in itertools.groupby(list_of_dts, key=lambda d: d.date())] 
+0

Es bueno saberlo - ¡gracias! Sin embargo, no maneja el requisito de una lista vacía para los días faltantes. –

+0

@Alex Ahh, de hecho, de alguna manera no me di cuenta de ese punto. – qiao

1

llenar los vacíos:

date_dict = {} 
for date_value in list_of_dates: 
    if date_dict.has_key(date_value.date()): 
     date_dict[date_value.date()].append(date_value) 
    else: 
     date_dict[date_value.date()] = [ date_value ] 
sorted_dates = sorted(date_dict.keys()) 
date = sorted_dates[0] 
while date <= sorted_dates[-1]: 
    print date_dict.get(date, []) 
    date += datetime.timedelta(1) 

Resultados:

[datetime.datetime(2012, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 1, 0)] 
[datetime.datetime(2012, 1, 2, 0, 0)] 
[datetime.datetime(2012, 1, 3, 0, 0)] 
[] 
[datetime.datetime(2012, 1, 5, 0, 0)] 

Esta solución no requiere la clasificación de la lista de fecha y hora original.

1
list_of_dts = [ 
      datetime.datetime(2012,1,1,0,0,0), 
      datetime.datetime(2012,1,1,1,0,0), 
      datetime.datetime(2012,1,2,0,0,0), 
      datetime.datetime(2012,1,3,0,0,0), 
      datetime.datetime(2012,1,5,0,0,0), 
      ] 

groupedByDay={} 
for date in list_of_dts: 
    if date.date() in groupedByDay: 
     groupedByDay[date.date()].append(date) 
    else: 
     groupedByDay[date.date()]=[date] 

Ahora usted tiene un diccionario, donde la fecha es la clave y el valor es una lista de fechas similares.

y si se fijan en tener una lista en lugar

result = groupedByDay.values() 
result.sort() 

ahora resulta es una lista de listas, donde todas las citas con el mismo día se agrupan

+2

'date.date() en groupedByDay.keys()' es O (n). ¿Podría reemplazarlo con 'date.date() en groupedByDay'? es O (1) – reclosedev

+0

hecho. Gracias por el consejo. Recién recogí Python ... Aprendí algo nuevo todos los días. – Lex