2016-07-01 46 views
14

Ho un compito per creare insiemi di date in base a condizioni specifiche, ad esempio "maggiore di 2" verrà passato e ho bisogno di creare un insieme di tutte le date in questo mese che hanno un giorno> 2. Anche io sto ricevendo un orario di inizio e un orario di stop per es 10:00-18:00 in questo caso voglio creare un insieme di tutte le date> 2 e in ogni giorno ha un momento di iniziare alle 10 e le estremità e 6:00, sotto è un esempio:confronta l'elenco di data/ora per indicare data/ora

greater > 2 less < 9 
start time :10am 
stop time :6 pm 
month:july 
date1: 2016-07-03 10:00, 2016-07-03 16:00 
date2: 2016-07-04 10:00, 2016-07-04 16:00 
date3: 2016-07-05 10:00, 2016-07-05 16:00 
. 
. 
. 
date6: 2016-07-8 10:00, 2016-07-8 16:00 

ho deciso di archiviare queste date in un dizionario come il seguente:

dictD = {'dates_between_2_9':[[2016-07-03 10:00, 2016-07-03 16:00], [2016-07-04 10:00, 2016-07-04 16:00], ....., [2016-07-08 10:00, 2016-07-08 16:00]]} 

ho usato il dict perché avrò più condizioni che ho bisogno di creare insiemi di date per loro, quindi non ci sarà ad esempio un altro tasto diverso da dates_between_2_5.

presso altra parte ottengo un'altra richiesta sulla base di una condizione troppo per creare le date con l'ora di inizio solo come la seguente:

greater > 1 less than 12 
start time : 2pm 
    date1: 2016-07-02 14:00 
    date2: 2016-07-03 14:00 
    date3: 2016-07-04 14:00 
    . 
    . 
    . 
    date10: 2016-07-11 14:00 

ho deciso di archiviare queste date in un elenco:

listL = [2016-07-02 14:00,2016-07-03 14:00,2016-07-04 14:00 ... 2016-07-11 14:00] 

dopo aver confrontato ogni data da ListL all'elenco di date per ogni chiave da DictD e se una data da ListL si trova all'interno di un punto di inizio, ora di arresto, dovrei rimuoverlo dall'elenco e restituire solo le date da ListL che non si sovrappongono con le date di DictD, la mia logica è come il seguito ing:

for L from ListL: 
    for every key in DictD: 
     for item from DictD[key]: 
      if DictD[key][0] < L < DictD[key][1] # check if item from list overlap with start,stop time from dictionary. 
       ListL.remove(L) # I know I can't remove items from list while iterating so I will probably create a set and store all overlapped items and then subtract this set to set(ListL) to get the difference. 
return ListL 

La mia domanda è: sto utilizzando una struttura dati efficiente per gestire i miei requisiti? Vedo che la mia logica non è così efficiente, quindi mi chiedevo se c'è un modo migliore per affrontare questo problema?

qualsiasi aiuto sarebbe molto apprezzato. grazie in anticipo!

+0

Un piccolo consiglio off-topic, non inserire uno zero iniziale sulle costanti integer. In Python 2 potresti ottenere un valore che non intendevi, e in Python 3 genera un errore (ad eccezione di '00'). –

risposta

1

Francamente io non sono sicuro se ho capito qual è il tuo problema, ho provato qualcosa di simile:

for date in dateList: 
    for everyrange in dateRange: 
     find=False 
     for i in dateRange[everyrange]: 
      #print('date={date} ,key={everyrange},i={i}'.format(date=date, everyrange=everyrange,i=i)) 
      if i[0] <= date <= i[1]: 
       print(date) 
       find=True 
       break 
      else: 
       print(0) 
     if find: 
      break 
+0

grazie per la tua risposta ma la tua risposta non restituisce la risposta giusta a causa delle pause – tkyass

1

Non sono sicuro di aver pienamente capito la tua domanda, ma io parto dal presupposto che si desidera trovare il date dalla lista 'dateList' che rientrano in un intervallo specifico nel 'dateRange' dic.

Ho provato a strutturare il mio codice in base alla logica. Questo dovrebbe funzionare:

for date in dateList: 
    for key,value in dateRange.items(): 
     for i in range(0,len(value)): 
      if date>=value[i][0] and date<=value[i][1]: 
       print('The date:',date,'lies between the data points:',value[i][0],'and',value[i][1],'in',key) 

nei dati, il DATERANGE DIC contiene le chiavi ('range') e valori, che sono liste di 2 oggetti datetime. Con il codice che ho fornito, dateRange dic può avere tutte le chiavi che vuoi e ogni valore di chiave può contenere tutti gli elenchi di oggetti datetime che desideri.

+0

grazie per la tua risposta ma la tua risposta fa esattamente la stessa funzionalità del codice che ho fornito – tkyass

1

Ho provato questo esempio, in base alla richiesta e ha funzionato bene =). L'algoritmo è molto simile a quello che hai postato, l'unica differenza è alla fine dell'algoritmo. Ho scelto di creare una nuova lista, da restituire nella funzione che stai creando.

Ecco il codice:

list_1 = ['a 1', 'a 2', 'a 3', 'a 4', 'a 5', 'b 1', 'b 2', 'b 3', 'b 4', 'b 5', 'c 1', 'c 2', 'c 3', 'c 4', 'c 5'] 
dict = {'example_between_2_5': [['a 3', 'a 4'], ['b 3', 'b 4'], ['c 3', 'c 4']]} 
new_list = [] 


# Defining the number of repetitions based on how many 'lists' inside the dict you have. 
for x in range(0, len(dict['example_between_2_5'])): 
    dict_list_elements = dict['example_between_2_5'][x] 
    # Defining the number of repetitions based on the elements inside the list of the dict. 
    for y in range(0, len(dict_list_elements)): 
     #Picking the element 
     dict_list_element = dict_list_elements[y] 
     for z in range(0, len(list_1)): 
      #Comparing to all elements in list_1 
      if dict_list_element == list_1[z]: 
       #The element will be append if doesn't exist in the new list 
       if list_1[z] not in new_list: 
        new_list.append(list_1[z]) 

#Printing the result just to check if it worked. 
print("list_1: ", list_1) 
print("New_list: ", new_list) 

Speranza che aiuta =)

5

Suona come si sta cercando di ottimizzare il vostro algoritmo. Per essere onesti, con dati di queste dimensioni, probabilmente non è necessario. Tuttavia, se sei interessato, la regola generale è quella sets are faster than lists in Python durante il controllo dell'appartenenza.

In questo caso, non è chiaro quali potrebbero essere i tuoi set. Ho assunto che tu abbia al massimo un livello di granularità di un minuto, ma potresti andare più in basso (per più memoria) o migliorare effettivamente l'occupazione e le prestazioni andando verso una granularità più ampia - ad es. ore. Questo codice mostra anche relativamente grandi insiemi possono essere almeno 5 volte più veloce (e guardare un po 'più semplice se si confrontano i set di dati):

from copy import copy 
from datetime import datetime, timedelta 
from timeit import timeit 
import time 

def make_range(start, open, close, days): 
    result = [] 
    base_start = start + open 
    base_close = start + close 
    while days > 0: 
     result.append([base_start, base_close]) 
     base_start += timedelta(days=1) 
     base_close += timedelta(days=1) 
     days -= 1 
    return result 

def make_range2(start, open, close, days): 
    result = set() 
    base_start = start + open 
    base_close = start + close 
    while days > 0: 
     now = base_start 
     while now <= base_close: 
      result.add(now) 
      now += timedelta(minutes=1) 
     base_start += timedelta(days=1) 
     base_close += timedelta(days=1) 
     days -= 1 
    return result 

dateRange = { 
    'range1': make_range(datetime(2016, 7, 3, 0, 0), 
         timedelta(hours=10), 
         timedelta(hours=18), 
         6), 
} 

dateRange2 = { 
    'range1': make_range2(datetime(2016, 7, 3, 0, 0), 
          timedelta(hours=10), 
          timedelta(hours=18), 
          6), 
} 

dateList = [ 
    datetime(2016, 7, 2, 14, 0), 
    datetime(2016, 7, 3, 14, 0), 
    datetime(2016, 7, 4, 14, 0), 
    datetime(2016, 7, 5, 14, 0), 
    datetime(2016, 7, 6, 14, 0), 
    datetime(2016, 7, 7, 14, 0), 
    datetime(2016, 7, 8, 14, 0), 
    datetime(2016, 7, 9, 14, 0), 
    datetime(2016, 7, 10, 14, 0), 
    datetime(2016, 7, 11, 14, 0) 
] 

dateSet = set(dateList) 

def f1(): 
    result = copy(dateList) 
    for a in dateList: 
     for b in dateRange: 
      for i in dateRange[b]: 
       if i[0] <= a <= i[1]: 
        result.remove(a) 
    return result 

def f2(): 
    result = copy(dateSet) 
    for b in dateRange2: 
     result = result.difference(dateRange2[b]) 
    return result 

print(f1()) 
print(timeit("f1()", "from __main__ import f1", number=100000)) 

print(f2()) 
print(timeit("f2()", "from __main__ import f2", number=100000)) 

Per la cronaca, i risultati sono i seguenti:

[datetime.datetime(2016, 7, 2, 14, 0), datetime.datetime(2016, 7, 9, 14, 0), datetime.datetime(2016, 7, 10, 14, 0), datetime.datetime(2016, 7, 11, 14, 0)] 
1.922587754837455 

{datetime.datetime(2016, 7, 2, 14, 0), datetime.datetime(2016, 7, 9, 14, 0), datetime.datetime(2016, 7, 10, 14, 0), datetime.datetime(2016, 7, 11, 14, 0)} 
0.30558400587733225 

È anche possibile convertire la data dateRange in una lista, ma con solo 1 o 2 membri, è improbabile che ciò possa fare la differenza nelle prestazioni. Tuttavia, ha un senso più logico, dal momento che in realtà non stai usando il dict per cercare valori specifici di una chiave - stai semplicemente iterando attraverso tutti i valori.

+0

Mi piace la tua risposta ma mi chiedo sulla parte dove crei un intervallo ogni volta che vogliamo confrontare, influisce sulle prestazioni? – tkyass

+0

@tkyass Posso avere una riproduzione rapida per vedere ... Per essere chiari, intendi la riga in cui duplica la dataSet/dataList (a seconda della funzione che chiami)? –

1

Non sono ancora assolutamente certo di ciò che stai cercando di ottenere, ma per favore guarda questo codice e dimmi se questo è quello che vuoi.

C'è un'opzione per inserire anche il mese.

L'elenco denominato elenco1 equivale al tuo dizionario dictD.

L'elenco denominato list2 è equivalente alla lista di elencoL. Questo ha solo quelle date che non si sovrappongono a quelle di list1 (dictD).

Ecco il codice.

from datetime import datetime 

#Converts 12-hour(am/pm) to 24-hour format 
def get_time(time): 
    digit = int(time[0:-2]) 
    if time[-2:] == 'am': 
     return digit 

    else: 
     return digit+12 


month_number = { 
    'january':1, 'february':2, 'march':3, 'april':4, 'may':5, 'june':6, 
    'july':7, 'august':8, 'september':9, 'october':10, 'november':11, 'december':12 
} 

gt1 = input('Enter first set\ngreater > ') 
lt1 = input('less < ') 

start1 = raw_input('start time: ') 
stop1 = raw_input('stop time: ') 

month1 = raw_input('month: ') 


gt2 = input('\nEnter second set\ngreater > ') 
lt2 = input('less < ') 

start2 = raw_input('start time: ') 

month2 = raw_input('month: ') 

list1 = [] 
list2 = [] 

today = datetime.today() 

start1 = get_time(start1) 
stop1 = get_time(stop1) 
start2 = get_time(start2) 

key = 'dates_between_%s_%s'%(gt1, gt2) 

for i in range(gt1+1, lt1): 
    list1.append(
      [ 
      datetime(today.year, month_number[month1], i, start1, 0).strftime("%Y-%m-%d %H:%M"), 
      datetime(today.year, month_number[month1], i, stop1, 0).strftime("%Y-%m-%d %H:%M") 
      ] 
     ) 

for i in range(gt2+1, lt2): 
    if (month1 == month2) and (gt1 < i < lt1) and (start1 < start2 < stop1): 
     pass 
    else: 
     list2.append(datetime(today.year, month_number[month2], i, start2, 0).strftime("%Y-%m-%d %H:%M")) 

print 'List1:\n',list1 
print '\nList2:\n',list2