Выберите диапазон дат в словаре Python - PullRequest
3 голосов
/ 01 августа 2011

У меня есть следующий словарь:

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. Даты не являются непрерывными.

Пока что я могу подумать:

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

Есть ли более эффективный способ сделать это?

ОБНОВЛЕНИЕ (2 августа 2011 г.)
Я нашел класс SortedCollection в ActiveState, также Раймонда Хеттингера.

Ответы [ 5 ]

5 голосов
/ 01 августа 2011

Я бы просто перебрал словарь и возвратил соответствующие элементы:

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

Обратите внимание, что ваш конкретный формат даты позволяет напрямую сравнивать строки с < и > без преобразования в datetime экземпляр первый.

Также обратите внимание, что данная функция будет возвращать совпадающие элементы в произвольном порядке.

0 голосов
/ 01 августа 2011

Это проходит через строку дат только один раз, сначала за счет сортировки списка.

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
0 голосов
/ 01 августа 2011
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)
0 голосов
/ 01 августа 2011
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'))  

Даты являются строками 'гггг-мм-дж'

Сортировка лексикографически этих строк приводит к тому же результату, что и сортировка по датам, которые они представляют.

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')) 
0 голосов
/ 01 августа 2011

Как насчет:

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]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...