2016-07-01 16 views
14

Mam zadanie do tworzenia zestawów dat na podstawie konkretnego warunku, na przykład "większy niż 2" zostanie przekazany i muszę utworzyć zestaw wszystkich dat w tym miesiącu, które mają dzień> 2. Również dostaję czas rozpoczęcia i czas zatrzymania dla np 10 am-6pm w tym przypadku będzie utworzyć zbiór wszystkich terminów> 2 iw każdym dniem ma czas, aby rozpocząć o godzinie 10, a kończy i 6pm, poniżej przykład:porównaj listę datetime do dykcji datetime

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 

zdecydowałem się zapisać terminy te w słowniku jak poniżej:

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]]} 

użyłem dict bo mam wiele warunków, które trzeba utworzyć zestawy dat dla nich, więc nie będzie na przykład inny klucz innego niż dates_between_2_5.

co z drugiej strony mam kolejny wniosek na podstawie warunku zbyt stworzyć daty z godziną rozpoczęcia tylko tak:

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 

postanowiłem zapisać te daty w formie listy:

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

potem porównuję każdą datę z ListL z listą dat dla każdego klucza z DictD i jeśli data z ListL leży w czasie rozpoczęcia, zatrzymania, to powinienem usunąć ją z listy i zwrócić tylko daty z listy nie pokrywają się z datami z DictD, moja logika jest jak następująca In:

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 

Moje pytanie brzmi: czy używam wydajnych struktur danych do obsługi moich wymagań? Widzę, że moja logika nie jest tak skuteczna, więc zastanawiałem się, czy istnieje lepszy sposób na rozwiązanie tego problemu?

każda pomoc byłaby bardzo doceniana. z góry dzięki!

+0

Nieodpowiednia rada, nie umieszczaj początkowego zera na stałych całkowitych. W Pythonie 2 możesz uzyskać wartość, której nie chcesz, aw Pythonie 3 generuje błąd (z wyjątkiem '00'). –

Odpowiedz

1

Szczerze mówiąc nie jestem pewien, czy rozumiem, o co ci chodzi, próbowałem coś takiego:

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

dziękuję za odpowiedź, ale twoja odpowiedź nie zwraca poprawnej odpowiedzi z powodu przerw – tkyass

1

Nie jestem pewien, czy w pełni zrozumiałe pytanie, ale jestem zakładając chcesz znaleźć pochodzi z listy "dateList", która mieści się między określonym zakresem w dicku "dateRange".

Próbowałem skonstruować mój kod na podstawie Twojej logiki. To powinno działać:

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) 

w danych, DATERANGE DIC zawiera klucze („Zakres”) i wartości, które są wykazy 2 obiektów datetime. Za pomocą podanego kodu DateRange dic może mieć dowolną liczbę kluczy, a wartość każdego klucza może zawierać tyle list obiektów datetime, ile chcesz.

+0

dziękuję za odpowiedź, ale twoja odpowiedź ma dokładnie taką samą funkcjonalność jak kod podany – tkyass

1

Próbowałem tego przykładu, w oparciu o Twoje żądanie i działało dobrze =). Algorytm jest bardzo podobny do tego, który opublikowałeś, jedyna różnica występuje na końcu algorytmu. Wybieram utworzenie nowej listy, która zostanie zwrócona w funkcji, którą budujesz.

Oto kod:

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) 

Nadzieja pomaga =)

5

Brzmi jak próbujesz optymalizacji algorytmu. Szczerze mówiąc, przy danych o tej wielkości, prawdopodobnie nie jest to konieczne. Jeśli jednak jesteś zainteresowany, ogólna zasada jest taka, że ​​podczas sprawdzania członkostwa jest sets are faster than lists w Pythonie.

W tym przypadku nie jest jasne, jakie mogą być twoje zestawy. Założę się, że masz najwyżej minutę szczegółowości, ale możesz obniżyć (dla większej ilości pamięci) lub faktycznie poprawić obłożenie i wydajność, przechodząc do większej ziarnistości - np. godziny. Kod ten pokazuje nawet stosunkowo duże zestawy mogą być co najmniej 5x szybciej (i wyglądają trochę prostsze przy porównywaniu swoich zestawów danych):

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)) 

Dla przypomnienia, wyniki są następujące:

[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 

Można również przekonwertować wartość dateict na dict, ale z zaledwie 1 lub 2 członkami, jest mało prawdopodobne, aby miało to jakikolwiek rzeczywisty wpływ na wydajność. Jednak ma to bardziej logiczny sens, ponieważ nie używasz dyktowania do wyszukiwania określonych wartości kluczowych - po prostu przechodzisz przez wszystkie wartości.

+0

Podoba mi się twoja odpowiedź, ale zastanawiam się nad częścią gdzie tworzysz zakres za każdym razem, gdy chcemy go porównywać, czy wpływa on na wydajność? – tkyass

+0

@tkyass Mogę szybko obejrzeć, żeby zobaczyć ... Aby było jasne - masz na myśli linię, w której duplikuję dateSet/dateList (w zależności od funkcji, którą wywołujesz)? –

1

Nadal nie jestem całkowicie pewien, co próbujesz osiągnąć, ale proszę spojrzeć na ten kod i powiedz mi, czy to jest to, czego chcesz.

Istnieje również możliwość wprowadzenia miesiąca.

Lista o nazwie lista1 jest odpowiednikiem słownika dictD.

Lista o nazwie list2 jest odpowiednikiem listy listL. Ma tylko te daty, które nie pokrywają się z tymi na liście 1 (dictD).

Oto kod.

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