在Python字典中选择一系列日期

时间:2011-08-01 13:29:51

标签: python date dictionary range

我有以下字典:

history = {
"2008-11-17": 41, 
"2010-05-28": 82, 
"2008-11-14": 47, 
"2008-11-13": 60, 
"2008-11-12": 56, 
"2008-11-11": 55, 
"2008-11-10": 98, 
"2008-11-19": 94, 
"2008-11-18": 94, 
"2004-05-27": 82, 
"2004-05-26": 45, 
"2004-05-25": 70,
# there's more ...
}

如何定义生成器函数get_records(dict_history, str_from_date, str_to_date)以生成date: record条目?

我知道如何将datetime个对象转换为我想要的任何字符串格式。然而,我在这个障碍中的主要痛点是:

  1. dict未订购。
  2. dict键是字符串。
  3. 日期不连续。
  4. 到目前为止,这是我能想到的:

    from datetime import datetime, timedelta
    
    def get_records(history, start_date, end_date):
      fmt = "%Y-%m-%d"
      dt = timedelta(days=1)
    
      present_date = datetime.strptime(start_date, fmt)
      end_date = datetime.strptime(end_date, fmt)
    
      while present_date <= end_date:
        present_string = present_date.strftime(fmt)
        try:
          yield (present_string, history[present_string])
        except KeyError:
          pass
        present_date += dt
    

    有更有效的方法吗?

    更新(2011年8月2日)
    我在ActiveState找到了一个SortedCollection课,也是由Raymond Hettinger创建的。

5 个答案:

答案 0 :(得分:5)

我只是迭代字典并返回匹配的项目:

def get_records(history, start_date, end_date):
    for date, entry in history.iteritems():
        if start_date <= date <= end_date:
             yield date, entry

请注意,您的特定日期格式允许与<>进行直接字符串比较,而无需先转换为datetime实例。

另请注意,给定的函数将以无特定顺序返回匹配项。

答案 1 :(得分:0)

怎么样:

def get_records(history, start_date, end_date, format = "%Y-%m-%d"):
    present_date = datetime.strptime(start_date, format)
    end_date = datetime.strptime(end_date, format)
    return [(key, value) for key, value in history.items() if present_date <= datetime.strptime(history[key], format) <= end_date]

答案 2 :(得分:0)

history = { "2008-11-17": 41,
            "2010-05-28": 82,
            "2008-11-14": 47,
            "2008-11-13": 60,
            "2008-11-12": 56,
            "2008-11-11": 55,
            "2008-11-10": 98,
            "2008-11-19": 94,
            "2008-11-18": 94,
            "2004-05-27": 82,
            "2004-05-26": 45,
            "2004-05-25": 70  }



def get_records(dict_history, str_from_date, str_to_date):

    for k,v in sorted(dict_history.items()):
        if k>str_to_date:
            break
        if k>=str_from_date:
            yield (k,v)

print history.items()
print
print list( get_records(history, '2005-05-21', '2008-12-25'))  

日期是字符串'yyyy-mm-jj'

按字典顺序排序这些字符串会产生与根据它们所代表的日期对它们进行排序相同的结果。

sorted(dict_history.items())是一个元组列表。 Python根据元组的第一个元素对此列表进行排序 字典中的每个键都是唯一的,这种排序没有歧义。

编辑1

回答您的表现问题:

history = { "2008-11-17": 41,
            "2010-05-28": 82,
            "2008-11-14": 47,
            "2008-11-13": 60,
            "2008-11-12": 56,
            "2008-11-11": 55,
            "2008-11-11": 02,
            "2008-11-10": 98,
            "2008-11-19": 94,
            "2008-11-18": 94,
            "2004-05-27": 82,
            "2004-05-26": 45,
            "2004-05-25": 70  }
import bisect

def get_records(dict_history, str_from_date, str_to_date):
    sorted_keys  = sorted(dict_history.iterkeys())
    start = bisect.bisect_left(sorted_keys,str_from_date)
    end   = bisect.bisect_right(sorted_keys,str_to_date)
    for date in sorted(dict_history.iteritems())[start:end]:
        yield date

print history.items()
print
print list( get_records(history, '2005-05-21', '2008-12-25')) 

答案 3 :(得分:0)

def get_records(history, str_from_date, str_to_date)
    return sorted((k,v) for k,v in history.iteritems() if str_from_date<=k<=str_to_date)

答案 4 :(得分:0)

这只会通过一行日期,而不是首先对列表进行排序。

from datetime import datetime, timedelta

def get_records(history, start_date, end_date):
  fmt = "%Y-%m-%d"

  start_date = datetime.strptime(start_date, fmt)
  end_date = datetime.strptime(end_date, fmt)

  dt = history.iteritems()
  dt = sorted(dt, key= lambda date: datetime.strptime(date[0], fmt))

  for date in dt:
      if datetime.strptime(date[0],fmt) > end_date:
          break
      elif datetime.strptime(date[0],fmt) >= start_date:
          yield(date[0], history[date[0]])
      else:
          pass