'dropwhile'是静态的吗?我可以让它动态吗?

时间:2012-08-25 05:24:13

标签: python itertools

简介

我想出了一个解决我问题的狡猾解决方案,但不是那么狡猾,它不起作用: - /

点击调试器后几小时我,所以也许你可以验证一下,它不起作用的原因是因为itertools.dropwhile在初始声明之后被修复了 - 而我希望我可以在每个循环中将输入参数更改为谓词。

下面的任务尝试选择一个startdate,然后是一个跟随它的enddate,然后是一个跟随它的startdate,以及一个跟在它之后的enddate ......依此类推,以便我们最终得到一系列日期间隔哪个不重叠。 startdates来自一个列表,而enddates来自另一个列表。

以下解决方案循环开始日期,然后循环结束日期,使用dropwhile传递“过去”中的日期。它第一次完美地工作。但是在第二轮比赛中,终结日被困在'2009-12-14'。我打破了“isbefore”例程,所以我可以看到它何时被测试,什么时候没有。不确定,但我认为正在发生的事情是整个dropwhile测试在第一次传递中一成不变,并且不会在每次传递时重新编译?就像我希望/期望的那样。

为了完成它我希望将它全部包含在while True内并通过StopIteration异常退出,从而提取完整的间隔序列。但它永远不会开火。当我尝试时,迭代器实际上都不会“下一步”到达终点。

问题

  1. 那个(一成不变的结论)是否正确发生了什么?
  2. 是否有一种简短,干净,优雅的方式使其表现得像我希望的那样?我是否必须按照我想要的方式编写自己的dropwhile?
  3. 代码

    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的工作原理。

1 个答案:

答案 0 :(得分:4)

一旦dropwhile删除了满足谓词的项,它就会产生未修改的其余可迭代项。在其位置使用itertools.ifilterfalse可提供所需的输出,因为即使在初始运行后它也会继续处理谓词。