介绍
我想出了一个巧妙的方法来解决我的问题,但是,不是那么狡猾,它不起作用:-/
在几个小时点击调试器之后,我想,也许您可以验证一下,它不起作用的原因是,在初始声明之后,itertools.dropwhile
是固定的,而我希望可以在每个循环中将输入参数更改为谓词。
下面的任务尝试选择一个startdate,然后选择一个跟在它后面的enddate,然后选择一个跟在它后面的startdate,最后一个之后的enddate。。。等等,这样我们就得到了一系列不重叠的日期间隔。开始日期来自一个列表,结束日期来自另一个列表。
下面的解决方案循环遍历startdate,然后遍历enddates,使用dropwhile
传递“过去”中的日期。它在第一次通过时工作得很好。但在第二次通过时,结束日期被固定在“2009-12-14”。我开始了“isbefore”程序,这样我就可以看到它什么时候被测试,什么时候不被测试。我不确定,但我想发生的事情是,整个dropwhile
测试在第一次通过时就成了石头,而不是在每次通过时都重新编译自己?如我所愿。
为了完成它,我希望将它全部封装在while True
中,并通过StopIteration
异常退出,从而提取完整的间隔序列。但它从不开火。当我尝试时,两个迭代器实际上都不会一直“next”到底。
问题
关于发生了什么事,这(一成不变的结论)是正确的吗?
有没有一种简洁,干净,优雅的方式让它像我所希望的那样?我必须写我自己的作品,而我想做什么呢?
代码
import itertools
import datetime
startdates = [
datetime.date(2009, 11, 5), datetime.date(2009, 11, 13),
datetime.date(2009, 12, 4), datetime.date(2009, 12, 7),
datetime.date(2009, 12, 29), datetime.date(2009, 12, 30)]
enddates = [
datetime.date(2009, 10, 1), datetime.date(2009, 10, 2),
datetime.date(2009, 11, 4), datetime.date(2009, 12, 14),
datetime.date(2009, 12, 15),datetime.date(2009, 12, 30)]
enddate = datetime.date(1900, 1, 1)
startdate = datetime.date(1900, 1, 1)
def isbefore(a, b):
return a <= b
for startdate in itertools.dropwhile(lambda date: isbefore(date, enddate), startdates):
for enddate in itertools.dropwhile(lambda date: isbefore(date, startdate), enddates):
print startdate, enddate
break
电流输出
2009-11-05 2009-12-14
2009-11-13 2009-12-14
2009-12-04 2009-12-14
2009-12-07 2009-12-14
期望输出
2009-11-05 2009-12-14
2009-12-29 2009-12-30
观察力更强的类型会注意到我昨天问了this question这个问题,但是这个问题需要一个通用的解决方案,而这次我特别问的是dropwhile的工作原理。
最佳答案
一旦dropwhile
删除了满足谓词的项,它将生成iterable的其余未修改项。在它的位置使用itertools.ifilterfalse
将提供您所需的输出,因为它将继续处理谓词,即使在初始运行之后也是如此。