首页 > 解决方案 > 从 Python Dict 返回具有日期时间范围的多个值

问题描述

我在使用 DateTime 作为 dict 键时遇到了问题。我的目标是从一个包含 Datetime 的数据源中引入信息,然后在字典中查找并返回输入 DateTime 的 2 天内 +- 内的所有键值。

例如,我的输入是: datetime.datetime(2018, 9, 20, 12, 48)

我要参考的字典是: example = {datetime.datetime(2018, 9, 20, 14, 43):'A', datetime.datetime(2018, 9, 18, 19, 41):'B', datetime.datetime(2018, 9, 15, 9, 12):'C'}

在这种情况下,我会返回:A, B

我考虑过对字典进行排序,然后为奇数日期创建索引字典,然后输入我的输入日期,计算输入日期的基准日期 +- 2,引用索引字典,然后使用这些索引仅在索引之间循环引用字典并返回所有存在的值。

我的主要问题是我无法预测字典日期时间或输入日期时间,所以我不确定是否可以返回字典中一系列键的值,而不是循环遍历键的索引以排序的顺序。在这里为所有键执行 for 循环效率不高,因为要查看的键的数量 - 我已经通过尽可能减少重复数据并仅引入最少量的参考数据来减少此列表。

另一项是我的输入将是 100,000 个要查找的日期时间,其中许多将彼此相隔几分钟、几秒或几小时,因此减少查找和 for 循环的数量对于保持运行时下降至关重要.

如果这不是一个需要查看完整代码的正确问题,我深表歉意,但我基本上不确定从哪里开始处理这个问题,所以我认为除了例如输入和具有输出目标的字典。

标签: pythonpython-2.7datetimedictionary

解决方案


  • 首先,对字典日期进行排序并将字典转换为已排序的元组列表:

    dic_dates = {
        datetime.datetime(2018, 9, 20, 14, 43):'A',
        datetime.datetime(2018, 9, 18, 12, 41):'B',
        datetime.datetime(2018, 9, 15, 9, 12):'C'
    }
    
    sorted_dates = sorted(dic_dates.items())
    
  • 然后使用 bisect 在该列表中查找您的日期的位置:

    dat = datetime.datetime(2018, 9, 20, 12, 48)
    insert_index = bisect.bisect_left(sorted_dates, (dat,None))
    
  • 从这个位置向左看,一旦元素不验证条件就中断,然后从右边的位置开始做同样的事情。(您可以使用自己的条件,因为我发现在您的示例中很不清楚 - +-2days 不应选择“B”IMO,但这不是重点)

    if insert_index:
    #if insert_index = 0, do not loop on left side
        dat_min = dat - datetime.timedelta(days=2)
        for d in sorted_dates[insert_index-1::-1]:
            if d[0] > dat_min:
                print(d[1])
            else:
                break
    
    dat_max = dat + datetime.timedelta(days=2)
    for d in sorted_dates[insert_index:]:
        if d[0] < dat_max:
            print(d[1])
        else:
            break
    

编辑

bisct_left 实现的一个示例:

def bisect_left(l, e, start = 0):
    if not l:
        return start
    pos = int(len(l)/2)
    if l[pos] < e and (pos+1 >= len(l) or l[pos+1] > e):
        return start + pos + 1
    elif l[pos] >= e:
        return bisect_left(l[:pos], e, start)
    else:
        return bisect_left(l[pos:], e, start+pos)

我强烈建议您使用 bisect,因为它会更快更可靠。


推荐阅读