代码之家  ›  专栏  ›  技术社区  ›  MyNameIsCaleb

从具有日期时间范围的python dict返回多个值

  •  1
  • MyNameIsCaleb  · 技术社区  · 6 年前

    我在使用datetime作为dict键时遇到问题。我的目标是从一个包含日期时间的数据源引入信息,然后在字典中查找并返回输入日期时间后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,并返回所有存在的值。

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

    另一个项目是,我的输入将是100000个要查找的日期时间,其中许多日期时间彼此相差几分钟、几秒或几小时,因此减少查找次数和循环将是保持运行时关闭的必要条件。

    如果这不是一个完整的代码可以看的很好的问题,我很抱歉,但我基本上不确定从哪里开始这个问题,所以我认为它不会帮助任何人把任何其他东西,除了输入和输出目标字典。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Corentin Limier    6 年前
    • 首先,对字典日期进行排序,并将字典转换为已排序的元组列表:

      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())
      
    • 然后用平分法找出你的约会对象在列表中的位置:

      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左执行的一个示例:

    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)
    

    我强烈建议你使用二分法,因为它会更快更可靠。