2016-07-01 32 views
14

Tôi có nhiệm vụ tạo bộ ngày dựa trên điều kiện cụ thể, ví dụ "lớn hơn 2" sẽ được chuyển và tôi cần tạo một tập hợp tất cả các ngày trong tháng này một ngày> 2. cũng Ill có thời gian bắt đầu và thời gian dừng cho ví dụ 10:00-18:00 trong trường hợp này tôi sẽ tạo ra một tập hợp của tất cả các ngày> 2 và trong mỗi ngày nó có một thời gian để bắt đầu lúc 10 giờ sáng và kết thúc và 6 giờ chiều, dưới đây là một ví dụ:so sánh danh sách datetime với dict của 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 

tôi quyết định để lưu trữ những ngày này thành một cuốn từ điển như sau:

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

tôi đã sử dụng dict vì tôi sẽ có nhiều điều kiện mà tôi cần để tạo ra bộ ngày đối với họ, vì vậy sẽ có ví dụ khác quan trọng khác hơn dates_between_2_5.

tại Mặt khác tôi nhận được một yêu cầu dựa trên một điều kiện quá để tạo ngày với thời gian bắt đầu chỉ như sau:

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 

tôi quyết định để lưu trữ những ngày này trong một danh sách:

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

sau đó tôi so sánh mỗi ngày từ ListL với danh sách ngày cho mỗi khóa từ DictD và nếu một ngày từ ListL nằm trong một bắt đầu, dừng thời gian sau đó tôi nên loại bỏ nó khỏi danh sách và chỉ trả về ngày từ ListL mà don không trùng lặp với ngày từ DictD, logic của tôi giống như sau 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 

Câu hỏi của tôi là tôi đang sử dụng cấu trúc dữ liệu hiệu quả để xử lý các yêu cầu của mình? Tôi thấy logic của tôi không hiệu quả nên tôi đã tự hỏi liệu có cách nào tốt hơn để tiếp cận vấn đề này không?

mọi trợ giúp sẽ được đánh giá cao. cảm ơn trước!

+0

Một chút tư vấn ngoài chủ đề, không đặt số 0 đứng đầu trên hằng số nguyên. Trong Python 2 bạn có thể nhận được một giá trị mà bạn không có ý định, và trong Python 3 nó tạo ra một lỗi (ngoại trừ '00'). –

Trả lời

1

Thẳng thắn mà nói tôi không chắc chắn nếu tôi hiểu vấn đề của bạn là gì, tôi đã cố gắng một cái gì đó như thế này:

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

cảm ơn câu trả lời của bạn nhưng câu trả lời của bạn không trả lời đúng vì bị ngắt – tkyass

1

Tôi không chắc chắn tôi hoàn toàn hiểu câu hỏi của bạn, nhưng tôi giả sử bạn muốn tìm ngày từ danh sách 'dateList' nằm trong phạm vi cụ thể trong 'dateRange' dic.

Tôi đã cố gắng cấu trúc mã của mình dựa trên logic của bạn. Điều này sẽ hoạt động:

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) 

Trong dữ liệu của bạn, dateRange dic chứa các khóa ('dải') và giá trị, là danh sách 2 đối tượng datetime. Với mã tôi đã cung cấp, dateRange dic có thể có bao nhiêu khóa tùy thích và giá trị của mỗi khóa có thể chứa nhiều danh sách đối tượng ngày giờ như bạn muốn.

+0

cảm ơn bạn đã trả lời nhưng câu trả lời của bạn thực hiện chính xác chức năng giống như mã tôi đã cung cấp – tkyass

1

Tôi đã thử ví dụ này, dựa trên nhu cầu của bạn và hoạt động tốt =). Thuật toán rất giống với thuật toán bạn đã đăng, sự khác biệt duy nhất nằm ở cuối thuật toán. Tôi chọn tạo một danh sách mới, được trả lại trong chức năng bạn đang xây dựng.

Dưới đây là các mã:

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) 

Hy vọng nó giúp =)

5

Có vẻ như bạn đang cố gắng để tối ưu hóa thuật toán của bạn. Thành thật mà nói, với dữ liệu kích thước này, có lẽ không cần thiết. Tuy nhiên, nếu bạn quan tâm, quy tắc chung của ngón cái là sets are faster than lists bằng Python khi kiểm tra thành viên.

Trong trường hợp này, không rõ bộ của bạn có thể là gì. Tôi đã giả định rằng bạn có mức chi tiết cao nhất trong một phút, nhưng bạn có thể xuống thấp hơn (để có nhiều bộ nhớ hơn) hoặc thực sự cải thiện khả năng sử dụng và hiệu suất bằng cách tăng mức độ chi tiết hơn - ví dụ: giờ. Mã này cho thấy thậm chí bộ tương đối lớn có thể có ít nhất 5x nhanh hơn (và tìm kiếm đơn giản hơn một chút khi so sánh bộ dữ liệu của bạn):

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

Đối với hồ sơ, kết quả như sau:

[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 

Bạn cũng có thể chuyển đổi dateDange của dict thành một danh sách, nhưng chỉ với 1 hoặc 2 thành viên, điều này sẽ không tạo ra bất kỳ sự khác biệt thực sự nào về hiệu năng. Tuy nhiên, nó có ý nghĩa hợp lý hơn, vì bạn không thực sự sử dụng dict để tìm kiếm bất kỳ giá trị khóa cụ thể nào - bạn chỉ đang lặp qua tất cả các giá trị.

+0

Tôi thích câu trả lời của bạn nhưng tôi tự hỏi về phần bạn tạo một phạm vi mỗi lần chúng tôi muốn so sánh, nó có ảnh hưởng đến hiệu năng không? – tkyass

+0

@tkyass Tôi có thể xem nhanh ... Để rõ ràng - bạn có nghĩa là dòng mà tôi sao chép dateSet/dateList (tùy thuộc vào chức năng bạn gọi)? –

1

Tôi vẫn không hoàn toàn chắc chắn những gì bạn đang cố gắng đạt được nhưng hãy xem mã này và cho tôi biết nếu đây là những gì bạn muốn.

Có một tùy chọn để nhập tháng.

Danh sách có tên list1 tương đương với từ điển dictD của bạn.

Danh sách có tên list2 tương đương với danh sách liệt kê của bạnL. Điều này chỉ có những ngày không trùng lặp với những ngày trong list1 (dictD).

Đây là mã.

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 
Các vấn đề liên quan