【问题标题】:Recursive list functions递归列表函数
【发布时间】:2016-07-20 13:28:11
【问题描述】:

我正在尝试创建一个递归 Python 函数,该函数接受一个周期列表并将它们合并到一个干净的时间线中。它应该扫描一个列表并应用这些规则:

  • 如果在时间段内发现 None 的值:将 None 替换为 datetime.date.today()

  • 如果一个句点开始于并且结束于另一个句点:删除它

  • 如果一个时期开始于结束于另一个时期:延长开始日期

  • 如果一个时期之后结束但另一个时期内开始:延长结束日期。

  • 如果一个时期之后开始并且另一个时期之后结束:保留它,它是一个单独的时期。

  • 如果一个时期开始于并且结束于另一个时期:保留它,它是一个单独的时期。

给出一个输入和期望输出的例子可能要容易得多(假设值是用日期时间格式化的)

[I] = [(01/2011, 02/2015), (04/2012, 08/2014), (09/2014, 03/2015), (05/2015, 06/2016)]
[O] = [(01/2011, 03/2015), (05/2015, 06/2016)]  
# Notice how the output has produced a set of minimum length whilst covering all periods.

[I] = [(07/2011, 02/2015), (04/2012, 08/2014), (09/2014, 04/2015), (06/2015, None)]
[O] = [(07/2011, 04/2015), (06/2015, date.today())]
# Also, notice how the output has amended None, so it can compare dates.

感谢@khredos,我写了以下内容,但它仍然没有输出所需的最小字符串:

from datetime import datetime

# Here is an example list of time periods
periods = [('01/2011', '02/2015'), ('04/2012', '08/2014'), ('09/2014', '03/2015'), ('05/2015', '06/2016')]

# this lambda function converts a string of the format you have specified to a 
# datetime object. If the string is None or empty, it uses today's date
cvt = lambda ds: datetime.strptime(ds, '%m/%Y') if ds else datetime.today()

# Now convert your original list to an iterator that contains datetime objects
periods = list(map(lambda s_e : (cvt(s_e[0]), cvt(s_e[1])), periods))

# Next get the start dates into one list and the end dates into another
starts, ends = zip(*periods)

# Finally get the timeline by sorting the two lists
timeline = sorted(starts + ends)

# Output: [datetime.datetime(2011, 1, 1, 0, 0), datetime.datetime(2012, 4, 1, 0, 0), datetime.datetime(2014, 8, 1, 0, 0), datetime.datetime(2014, 9, 1, 0, 0), datetime.datetime(2015, 2, 1, 0, 0), datetime.datetime(2015, 3, 1, 0, 0), datetime.datetime(2015, 5, 1, 0, 0), datetime.datetime(2016, 6, 1, 0, 0)]

【问题讨论】:

  • 请同时发布您遇到的“错误”
  • 感谢您的反馈。请查找添加到问题底部的错误。因为我试图篡改一对中的一半,所以我遇到了错误。
  • 元组是不可变的:你不能改变值。如果你想改变它,要么创建一个新的元组,要么使用一个列表。

标签: python list datetime recursion zip


【解决方案1】:
from datetime import datetime

# Here is an example list of time periods
periods = [('01/2011', '02/2015'), ('04/2012', '08/2014'), ('09/2014', '03/2015'), ('05/2015', '06/2016')]

# this lambda function converts a string of the format you have specified to a 
# datetime object. If the string is None or empty, it uses today's date
cvt = lambda ds: datetime.strptime(ds, '%m/%Y') if ds else datetime.today()

可用格式为here

# Now convert your original list to an iterator that contains datetime objects
periods = list(map(lambda s_e : (cvt(s_e[0]), cvt(s_e[1])), periods))

# Next get the start dates into one list and the end dates into another
starts, ends = zip(*periods)

# Finally get the timeline by sorting the two lists
timeline = sorted(starts + ends)

输出应该类似于

[datetime.datetime(2011, 1, 1, 0, 0), datetime.datetime(2012, 4, 1, 0, 0), datetime.datetime(2014, 8, 1, 0, 0), datetime.datetime(2014, 9, 1, 0, 0), datetime.datetime(2015, 2, 1, 0, 0), datetime.datetime(2015, 3, 1, 0, 0), datetime.datetime(2015, 5, 1, 0, 0), datetime.datetime(2016, 6, 1, 0, 0)]

尝试使用您拥有的任何日期列表,您应该会观察到相同的行为。

HTH

【讨论】:

  • 这太棒了!感谢您的快速回复并设法使代码简短而优美。由于我无法在 Python 3 中解包元组,因此出现错误。这条线正在倒下:“periods = map(lambda (s, e) : (cvt(s), cvt(e)), period)” .另外,输出不是列表,所以我不知道哪些日期被分组在一起。您能否更新您的答案以输出一个包含开始和结束日期的列表,就像输入列表一样?
  • @AaronAvocado,刚刚更新了使用 python 3 语法的答案。不幸的是,python 3 似乎不支持元组参数解包,这就是发生错误的原因。地图类还返回一个迭代器,这就是输出不是列表的原因。此编辑已全部修复
  • 太好了,感谢@khredos 的更新。唯一的问题是输出数组没有创建一个“干净”的时间线。日期('04/2015'、'08/2014')不应出现在输出中,因为它们属于期间('01/2011'、'02/2015')。该代码的目标是删除开始和结束在另一个中的句点;延长从内部开始但在外部结束或在另一个内部结束并在另一个外部开始的期间;开始和结束在另一个时段之外的时段应显示为单独的组。
猜你喜欢
  • 1970-01-01
  • 2016-01-22
  • 2015-04-19
  • 2023-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多