在一个时间范围内选择时隙的简洁有效的方法

时间:2018-06-27 13:22:54

标签: python python-2.7 performance datetime

我有一堆带有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]

但是有两个可选参数,minimum和maximum,表示时隙必须在最大分钟数之内且在最小分钟数之外。

我们有以下插槽:

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 :(得分:1)

这可以用间隔树有效地解决。参见https://en.wikipedia.org/wiki/Interval_tree

根据Google的快速搜索,似乎有很多python实现。

答案 1 :(得分:0)

您可以基于最大值和最小值创建lambda函数。然后在单个列表理解中应用该函数。

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]

此外,如果您对时间进行排序,找到最大值后就可以停止搜索。

答案 2 :(得分:0)

只需计算所有内容一次并设置有用的默认值:

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]