Сравнить список datetime с типом datetime

У меня есть задача создания наборов дат на основе определенного условия, например, "больше 2" будет передано, и мне нужно создать набор всех дат в этом месяце, у которых есть день > 2. Также Ill be be получение времени начала и времени остановки, например С 10:00 до 18:00 в этом случае я создам набор всех дат > 2 и каждый день у него будет время для начала в 10:00 и заканчивается и 6 вечера, ниже приведен пример:

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

Я решил сохранить эти даты в словаре следующим образом:

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

Я использовал dict, потому что у меня будет несколько условий, которые мне нужны для создания наборов дат для них, поэтому будет, например, другой ключ, отличный от date_between_2_5.

с другой стороны, я получаю другой запрос на основе условия также для создания дат со временем начала, только следующим образом:

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

Я решил сохранить эти даты в списке:

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

после этого я сравниваю каждую дату из списка ListL с списком дат для каждого ключа из DictD, и если дата из ListL находится в начале, остановите время, то я должен удалить его из списка и вернуть только даты из списка ListL, которые не перекрывайте даты с DictD, моя логика выглядит следующим образом:

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

Мой вопрос: использую ли я эффективные структуры данных для обработки моих требований? Я вижу, что моя логика не настолько эффективна, поэтому мне было интересно, есть ли лучший способ для решения этой проблемы?

любая помощь будет принята с благодарностью. спасибо заранее!

Ответы

Ответ 1

Похоже, вы пытаетесь оптимизировать свой алгоритм. Честно говоря, с данными такого размера, это, вероятно, не нужно. Однако, если вам интересно, общее правило состоит в том, что наборы быстрее, чем списки в Python при проверке членства.

В этом случае не ясно, какие могут быть ваши наборы. Я предположил, что у вас есть не более чем минутный уровень детализации, но вы можете пойти ниже (для большей памяти) или даже улучшить занятость и производительность, перейдя на более крупную детализацию - например, ч. Этот код показывает, что даже относительно большие наборы могут быть как минимум в 5 раз быстрее (и при сравнении ваших наборов данных немного проще):

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

Для записи результаты следующие:

[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

Вы также можете преобразовать dict dateRange в список, но с 1 или 2 членами, это вряд ли может иметь какое-то реальное различие в производительности. Однако это имеет более логичный смысл, поскольку вы фактически не используете dict для поиска каких-либо конкретных значений ключа - вы просто повторяете все значения.

Ответ 2

Честно говоря, я не уверен, понимаю ли я, в чем ваша проблема, я попробовал что-то вроде этого:

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

Ответ 3

Я не уверен, что полностью понял ваш вопрос, но предполагаю, что вы хотите найти даты из списка dateList, которые попадают между определенным диапазоном в диалоговом окне dateRange.

Я попытался структурировать свой код на основе вашей логики. Это должно работать:

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)

В ваших данных параметр dateRange содержит ключи ( "диапазон" ) и значения, которые представляют собой списки из двух объектов datetime. С предоставленным мной кодом, dateRange dic может иметь столько ключей, сколько вам нравится, и каждое значение ключа может содержать столько списков объекта datetime, сколько вам захочется.

Ответ 4

Я попробовал этот пример, исходя из вашего спроса и хорошо работавшего =). Алгоритм очень похож на тот, который вы опубликовали, единственное отличие в конце алгоритма. Я хочу создать новый список, который будет возвращен в создаваемой вами функции.

Здесь код:

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)

Надеюсь, что это поможет =)

Ответ 5

Я все еще не совсем уверен, чего вы пытаетесь достичь, но, пожалуйста, взгляните на этот код и скажите, действительно ли это то, что вы хотите.

Существует также возможность ввода месяца.

Список с именем list1 эквивалентен вашему словарю dictD.

Список с именем list2 эквивалентен списку listL. У этого есть только те даты, которые не совпадают с таковыми в списке1 (dictD).

Здесь код.

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