Сжатый и эффективный способ выбора временных интервалов во временном диапазоне - PullRequest
0 голосов
/ 27 июня 2018

У меня есть куча временных интервалов с началом и концом типа datetime. Учитывая конкретную дату и время, мне нужно получить те, которые были до и после:

def get_before(timeslots, moment):
    return [t for t in timeslots if t.end <= moment]

def get_after(timeslots, moment):
    return [t for t in timeslots if t.start >= moment]

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

У нас есть следующие слоты:

2018-06-27 09:00:00 - 2018-06-27 10:00:00
2018-06-27 10:00:00 - 2018-06-27 11:00:00
2018-06-27 11:00:00 - 2018-06-27 12:00:00
2018-06-27 12:00:00 - 2018-06-27 13:00:00
2018-06-27 13:00:00 - 2018-06-27 14:00:00
2018-06-27 14:00:00 - 2018-06-27 15:00:00
2018-06-27 15:00:00 - 2018-06-27 16:00:00
2018-06-27 16:00:00 - 2018-06-27 17:00:00
2018-06-27 17:00:00 - 2018-06-27 18:00:00
2018-06-27 18:00:00 - 2018-06-27 19:00:00
2018-06-27 19:00:00 - 2018-06-27 20:00:00
2018-06-27 20:00:00 - 2018-06-27 21:00:00
2018-06-27 21:00:00 - 2018-06-27 22:00:00

Если нам нужны временные интервалы после 2018-06-27 15:00:00, с минимумом 1 час и максимум 4 часа, мы получаем:

2018-06-27 16:00:00 - 2018-06-27 17:00:00
2018-06-27 17:00:00 - 2018-06-27 18:00:00
2018-06-27 18:00:00 - 2018-06-27 19:00:00
2018-06-27 19:00:00 - 2018-06-27 20:00:00

Это моя реализация:

def get_before(timeslots, moment, minimum=None, maximum=None):
    tslots = [t for t in timeslots if t.end <= moment]
    if maximum is not None:
        maxdelta = datetime.timedelta(minutes=maximum)
        tslots = [t for t in tslots if t.end + maxdelta >= moment]
    if minimum is not None:
        mindelta = datetime.timedelta(minutes=minimum)
        tslots = [t for t in tslots if t.end <= moment - mindelta]
    return tslots


def get_after(timeslots, moment, minimum=None, maximum=None):
    tslots = [t for t in timeslots if t.start >= moment]
    if maximum is not None:
        maxdelta = datetime.timedelta(minutes=maximum)
        tslots = [t for t in tslots if t.start - maxdelta <= moment]
    if minimum is not None:
        mindelta = datetime.timedelta(minutes=minimum)
        tslots = [t for t in tslots if t.start >= moment + mindelta]
    return tslots

Проблема в том, что для каждой функции фильтрации я повторяю список timeslots три раза: один, чтобы получить их до или после момента, во-вторых, чтобы получить их в пределах максимального временного диапазона, и в-третьих, чтобы отфильтровать те, которые находятся вне минимальный диапазон времени.

Эти функции будут вызываться очень часто, поэтому мне интересно, есть ли способ объединить фильтрацию, чтобы список повторялся только один раз.

Ответы [ 3 ]

0 голосов
/ 27 июня 2018

Это можно эффективно решить с помощью дерева интервалов. Смотри https://en.wikipedia.org/wiki/Interval_tree

По-видимому, существует много реализаций Python согласно быстрому поиску в Google.

0 голосов
/ 27 июня 2018

просто вычислите все один раз и установите полезные значения по умолчанию:

def get_before2(timeslots, moment, minimum=0, maximum=1440):
    maxdelta = moment - datetime.timedelta(minutes=maximum)
    mindelta = moment - datetime.timedelta(minutes=minimum)
    tslots = [t for t in timeslots if t.end >= maxdelta and t.end <= mindelta]  
0 голосов
/ 27 июня 2018

Вы можете создать лямбда-функцию на основе присутствия максимума и минимума. Затем примените эту функцию в едином понимании списка.

maximum = 10
minimum = 5

if maximum:
    f = lambda x : x <= maximum

if minimum:
    f = lambda x : x >= minimum

if maximum and minimum:
    f = lambda x : x <= maximum and x >= minimum


print [ x for x in range(50) if f(x) ]

выход:

[sri@localhost ~]$ python test.py
[5, 6, 7, 8, 9, 10]

Кроме того, если ваше время отсортировано, вы можете прекратить поиск, когда найдете максимальное значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...