Как найти пропущенные даты в списке отсортированных дат? - PullRequest
13 голосов
/ 23 февраля 2010

Как в Python найти все пропущенные дни в отсортированном списке дат?

Ответы [ 7 ]

21 голосов
/ 23 февраля 2010

с использованием наборов

>>> from datetime import date, timedelta
>>> d = [date(2010, 2, 23), date(2010, 2, 24), date(2010, 2, 25),
         date(2010, 2, 26), date(2010, 3, 1), date(2010, 3, 2)]
>>> date_set = set(d[0] + timedelta(x) for x in range((d[-1] - d[0]).days))
>>> missing = sorted(date_set - set(d))
>>> missing
[datetime.date(2010, 2, 27), datetime.date(2010, 2, 28)]
>>> 
4 голосов
/ 23 февраля 2010

Сортировка списка дат и итерация по нему, помня предыдущую запись. Если разница между предыдущей и текущей записью превышает один день, у вас есть пропущенные дни.

Вот один из способов реализовать это:

from datetime import date, timedelta
from itertools import tee, izip

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    b.next()
    return izip(a, b)

def missing_dates(dates):
    for prev, curr in pairwise(sorted(dates)):
        i = prev
        while i + timedelta(1) < curr:
            i += timedelta(1)
            yield i

dates = [ date(2010, 1, 8),
          date(2010, 1, 2),
          date(2010, 1, 5),
          date(2010, 1, 1),
          date(2010, 1, 7) ]

for missing in missing_dates(dates):
    print missing

Выход:

2010-01-03
2010-01-04
2010-01-06

Производительность O (n * log (n)), где n - количество дней в интервале, когда входные данные не отсортированы. Поскольку ваш список уже отсортирован, он будет работать в O (n).

2 голосов
/ 23 февраля 2010
>>> from datetime import datetime, timedelta
>>> date_list = [datetime(2010, 2, 23),datetime(2010, 2, 24),datetime(2010, 2, 25),datetime(2010, 2, 26),datetime(2010, 3, 1),datetime(2010, 3, 2)]
>>> 
>>> date_set=set(date_list)         # for faster membership tests than list
>>> one_day = timedelta(days=1)
>>> 
>>> test_date = date_list[0]
>>> missing_dates=[]
>>> while test_date < date_list[-1]:
...     if test_date not in date_set:
...         missing_dates.append(test_date)
...     test_date += one_day
... 
>>> print missing_dates
[datetime.datetime(2010, 2, 27, 0, 0), datetime.datetime(2010, 2, 28, 0, 0)]

Это также работает для datetime.date объектов, но ОП говорит, что список datetime.datetime объектов

1 голос
/ 23 февраля 2010

Поместите даты в set, а затем выполните итерации от первой до последней, используя datetime.timedelta(), проверяя наличие в наборе каждый раз.

0 голосов
/ 05 марта 2017

Хороший способ сделать это в Python заключается в следующем. Вам не нужно беспокоиться об эффективности, если в вашем списке нет дат из нескольких лет, и этот код всегда должен выполняться в соответствии с взаимодействием с пользователем и немедленно выводить результаты.

  1. Получить пропущенные даты из одного списка (отсортированы или нет)

Создайте функцию, которая дает вам все даты от start_date до end_date. И используйте это.

import datetime

def get_dates(start_date, end_date):
    span_between_dates = range(end_date - start_date).days
    for index in span_between_dates + 1:
        # +1 is to make start and end dates inclusive.
        yield start_date + datetime.timedelta(index)

my_date_list = ['2017-03-05', '2017-03_07', ...]
# Edit my_date_list as per your requirement.
start_date = min(my_date_list)
end_date = max(my_date_list)
for current_date in get_dates(start_date, end_date)
    if date not in my_date_list:
        print date
  1. Получить пропущенные или перекрывающиеся даты между двумя диапазонами дат.

get_dates функция должна быть определена.

my_other_date_list = []  # your other date range
start_date = min(my_date_list)
end_date = max(my_date_list)
for current_date in get_dates(start_date, end_date)
    if (date in my_date_range) and (date in my_other_date_list):
        print ('overlapping dates between 2 lists:')
        print date
    elif (date in my_date_range) and (date not in my_other_date_list):
        print ('missing dates:')
        print date
0 голосов
/ 23 февраля 2010

Использование списка понимания

>>> from datetime import date, timedelta
>>> d = [date(2010, 2, 23),date(2010, 2, 24),date(2010, 2, 25),date(2010, 2, 26),date(2010, 3, 1),date(2010, 3, 2)]
>>> date_set=set(d)
>>> missing = [x for x in (d[0]+timedelta(x) for x in range((d[-1]-d[0]).days)) if x not in date_set]

>>> missing
[datetime.date(2010, 2, 27), datetime.date(2010, 2, 28)]
0 голосов
/ 23 февраля 2010
import datetime

DAY = datetime.timedelta(days=1)
# missing dates: a list of [start_date, end)
missing = [(d1+DAY, d2) for d1, d2 in zip(dates, dates[1:]) if (d2 - d1) > DAY]

def date_range(start_date, end, step=DAY):
    d = start_date
    while d < end:
        yield d
        d += step

missing_dates = [d for d1, d2 in missing for d in date_range(d1, d2)]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...