【问题标题】:Returning multiple values from Python Dict with range of datetime从 Python Dict 返回具有日期时间范围的多个值
【发布时间】:2018-09-25 07:47:03
【问题描述】:

我在使用 DateTime 作为字典键时遇到了问题。我的目标是从一个包含 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,引用索引字典,然后使用这些索引仅在索引之间循环引用字典并返回所有存在的值。

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

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

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

【问题讨论】:

  • 你考虑过使用 SQL 数据库吗?
  • 很遗憾我不能使用 SQL 数据库,我受限于我展示的数据模型。

标签: python python-2.7 datetime dictionary


【解决方案1】:
  • 首先,对字典日期进行排序并将字典转换为已排序的元组列表:

    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,因为它会更快更可靠。

【讨论】:

  • 我认为这会起作用,并且与我的想法非常相似。目前,不允许使用 bisect 模块。我已要求将其重新打开,但在那之前,您知道另一种快速查找列表索引的方法吗?
  • 另外你说得对,B 实际上并不在里面,但我只是在写一些快速的日期,​​并没有在我的脑海中正确地做数学。我的实际情况将超过 2 天,但我试图简化。我将修改我的示例日期,以便将来的人不会感到困惑。
  • @GiraffeMan91 我编辑了 - 如果你有 numpy,你也可以使用 searchsorted from numpy
  • 您的代码与您的修改完美配合,直到我可以打开 bisect()。它现在无法完成大约 110,000 轮。我正在寻找可以进一步缩短时间的方法。我的数据实际上是关键:['item1','item2']。我的目标是使用 item1 返回出现的 item2 列表,但仅限于输入日期后 5 天 +- 内的记录。我完全从与日期混合的输入中匹配 item1。我可以在事先不知道所有 item1 是什么的情况下创建不同的字典 -> 名称基于 item1 的排序元组吗?
猜你喜欢
  • 1970-01-01
  • 2016-10-11
  • 1970-01-01
  • 1970-01-01
  • 2013-09-18
  • 2020-03-21
  • 1970-01-01
  • 2023-01-10
  • 2018-04-08
相关资源
最近更新 更多