2016-07-20 81 views
3

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

  • 如果值没有是在周期中发现:更换无与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)] 
+0

请还发布了什么“错误”要跨 –

+0

感谢来的反馈。请查找添加到问题底部的错误。我收到错误,因为我试图篡改一对中的一半。 – alpacinohead

+0

元组是不可变的:你不能改变这个值。如果你想改变它,可以创建一个新的元组或者使用一个列表。 – Prune

回答

2
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

+0

这太棒了!感谢您的快速回复,并尽量保持代码简短和甜蜜。由于我无法在Python 3中解开元组,因此我收到了错误。这条线正在下降:“句号=地图(lambda(s,e):(cvt(s),cvt(e)),句号)” 。 此外,输出不是一个列表,所以我不知道哪些日期分组在一起。您是否可以更新您的答案,以便像输入列表一样输出包含开始日期和结束日期的列表? – alpacinohead

+0

@AaronAvocado,刚刚更新了使用python 3语法的答案。不幸的是,它看起来像python 3不支持tuple参数解包,这就是错误发生的原因。此外,map类返回一个迭代器,这就是为什么输出不是列表。所有修正与此编辑 – smac89

+0

非常好,谢谢你的更新@khredos。唯一的问题是输出数组没有创建一个'干净'的时间表。日期('04/2015','08/2014')不应出现在输出中,因为它们在期限内('01/2011','02/2015')。该守则的目标是消除在另一个开始和结束的时段;延长在内部开始但在结束之外并且在另一个之外开始的期间;在另一个之外开始和结束的时间段应显示为一个单独的组。 – alpacinohead