如何计算日期列表中的连续天数


# below is the example of list of dates:
date_list = [date(2021, 1, 2), date(2021, 1, 3), date(2021, 1, 5)]

我正在考虑计算所有连续的日期,并制作一个字典,其中键值是开始日期,值是连续天数的计数。

dic = {date(2021, 1, 2): 2, date(2021, 1, 5): 1}
谁能告诉我应该采取什么步骤来完成上述任务?我应该用另一种方法来处理这个问题吗?非常感谢。

这更像是一个算法问题,这里我列出了带有一些测试用例的代码

from datetime import date
from datetime import timedelta

def is_consecutive(date1, date2):
return True if date1 + timedelta(days=1) == date2 else False

def my_func(date_list):
if not date_list:
return {}
if len(date_list) == 1:
return {date_list[0]: 1}
date_list.sort()
res = {}
start_date = date_list[0]
cnt = 1
for idx, cur_date in enumerate(date_list[1:], start=1):
# print(idx, cur_date)
if is_consecutive(date_list[idx - 1], cur_date):
cnt += 1
else:
res[start_date] = cnt
start_date = cur_date
cnt = 1
else:
res[start_date] = cnt
return res

if __name__ == "__main__":
# below is the example of list of dates:
date_list = [date(2021, 1, 2), date(2021, 1, 3), date(2021, 1, 5)]
# {datetime.date(2021, 1, 2): 2, datetime.date(2021, 1, 5): 1}
print(my_func(date_list))
date_list = [date(2021, 1, 5), date(2021, 1, 2), date(2021, 1, 3), date(2021, 1, 6), date(2021, 1, 31),
date(2021, 2, 1), date(2021, 2, 2)]
# {datetime.date(2021, 1, 2): 2, datetime.date(2021, 1, 5): 2, datetime.date(2021, 1, 31): 3}
print(my_func(date_list))
date_list = [date(2021, 1, 5)]
# {datetime.date(2021, 1, 5): 1}
print(my_func(date_list))
date_list = []
# {}
print(my_func(date_list))

您需要遍历date_list并将每个日期与前一个日期进行比较,以查看它们是否连续的日子。假设您正在使用内置的日期时间。您可以使用toordinal()方法来方便地比较日期。你也可以使用1天的时差。您将需要跟踪连续日期链中的第一个日期,以便您可以继续在字典中访问它。

假设您的日期列表已经排序,下面的代码应该可以工作。

from datetime import date
date_list = [date(2021, 1, 2), date(2021, 1, 3), date(2021, 1, 5)]
dic = {}
date_range_start = None
for i in range(len(date_list)):
if i == 0:
date_range_start = date_list[i]
dic[date_range_start] = 1
else:
if date_list[i].toordinal() - date_list[i-1].toordinal() == 1:
dic[date_range_start] += 1
else:
date_range_start = date_list[i]
dic[date_range_start] = 1

有不同的方法来解决你的问题。在这种情况下,一个简单而有效的方法是只使用for循环,检查条件(日期是连续的)是否适用于当前循环项目和"正在进行"的项目;日期组:

from datetime import date
date_list = [date(2021, 1, 2), date(2021, 1, 3), date(2021, 1, 5)]
result = {}
c = date_list[0]
n = 1
for d in date_list[1:]:
if (d - c).days == n:
n = n + 1
else:
result[c] = n
c = d
n = 1
result[c] = n
print(result)

我们从"组"开始其中我们放置第一个日期和计数器n,用于表示组中元素的数量。然后我们开始循环(从第二项开始)。在每次迭代中,我们检查条件:当前日期是否距离组中的第一个日期在未来n天?如果是,则增加n并继续,否则将数据存储在字典中。注意,我说的是一个"群体"。第一个日期和n(组跨越的天数)在这里就足够了。

重要:当使用此方法时,您总是需要考虑最后一组项需要在循环外处理的事实。

正如我所说的,还有其他方法:我选择这个方法是因为,恕我直言,它很容易理解它是如何工作的。

我会这样做:首先通过执行date_list.sort()对列表进行排序,这是相当重要的,因为如果没有排序,您将无法得到正确的结果。

然后使用for循环来迭代整个列表,通过设置变量current_date来跟踪前一天,将当前日期与前一天和当前日期进行比较,如果是连续的,则增加计数器如current_max_consecutive_day,否则用新日期和计数器重置前一个日期。

from datetime import date
date_list = [date(2021, 1, 2), date(2021, 1, 3), date(2021, 1, 5)]
date_list.sort() # if the list is not sorted, then please sort it
dic = {}
current_max_consecutive_day = 1
current_date = date_list[0]
# This only work if the list is sorted
for d in date_list:
if d.day-current_date.day == 1:
# if we found a consecutive day then add it to the dictionary
current_max_consecutive_day += 1
else:
# otherwise create a new item in the dic and restart the count
current_max_consecutive_day = 1
current_date = d
dic[current_date] = current_max_consecutive_day

您可以将列表转换为字典,每个日期计数为1。然后以每天为起始点合并连续的日期:

from datetime import date,timedelta
date_list = [date(2021, 1, 3), date(2021, 1, 2), date(2021, 1, 5)]
dic = dict.fromkeys(date_list,1) # start with each date = span of 1
for d in date_list:              # try to merge each date with next ones
c = d
while c in dic:                    # get consecutive dates starting from d
if c>d: dic[d] += dic.pop(c)   # merge/remove later date
c += timedelta(days=1)         # check further 

print(dic)
# {datetime.date(2021, 1, 2): 2, datetime.date(2021, 1, 5): 1}

即使日期不是按升序排列,这也可以工作,因此您不需要排序,并且将获得O(n)时间复杂度

请注意,此解决方案不考虑列表中重复日期的可能性(即即使列表中有多个实例,每个日期也只计算1)

相关内容

  • 没有找到相关文章

最新更新