【问题标题】:How to merge two lists of dates into a series of date intervals?如何将两个日期列表合并为一系列日期间隔?
【发布时间】:2012-08-19 15:00:38
【问题描述】:

我有开始日期列表和结束日期列表。它们已排序...

start_dates = [
    datetime.date(2009, 11, 5), datetime.date(2009, 11, 13), 
    datetime.date(2009, 11, 25), datetime.date(2009, 11, 26), 
    datetime.date(2009, 12, 4), datetime.date(2009, 12, 7), 
    datetime.date(2009, 12, 29), datetime.date(2009, 12, 30)]

end_dates = [
    datetime.date(2009, 10, 1), datetime.date(2009, 10, 2), 
    datetime.date(2009, 10, 9), datetime.date(2009, 10, 12), 
    datetime.date(2009, 11, 4), datetime.date(2009, 12, 14), 
    datetime.date(2009, 12, 15)]

开始日期表示我们收到建议购买股票的日期。结束日期是我们收到出售建议的日期。建议的来源是不同的,我们正在回测如果我们使用来自一个来源的买入建议,而使用来自另一个来源的卖出建议会发生什么。因此,我们有两个日期序列,我们希望将它们分解成对(或间隔),在这些日期序列中我们会在股票中持有头寸。

因此,我们将从 start_dates 中选择一个日期来决定何时购买股票:我们在 11 月 5 日买入一个头寸。然后我们在 end_dates 中循环寻找第一个卖出建议:12 月 14 日。然后重复,当我们从一个来源获得建议时没有持有头寸时买入,当我们从另一个来源持有头寸时卖出。

你可能会说我们想要在循环遍历的两个列表中的哪一个之间切换。

因此上面的输入生成:

result = (
  (datetime.date(2009, 11, 5), datetime.date(2009, 12, 14)),
  (datetime.date(2009, 12, 29), None)
)

我在 for 循环中使用 for 循环,想知道是否没有更好的方法。性能令人感兴趣,因为它将在 40 年的时间跨度内应用于数千种场景;有些列表涉及数千个日期。

【问题讨论】:

  • 您想要达到的结果看起来如何。很难从你希望结果如何的问题中说出来
  • @PabloKarlsson 我相信问题中已经指定了所需的结果?!这是一个日期元组列表。
  • 是的,但是如何映射它们(start_dates[1],end_dates[1])?
  • @PabloKarlsson 抱歉,您没有关注。我为你详细说明了q。
  • 没问题,我想我已经提供了答案,希望它适合你..

标签: python list date merge


【解决方案1】:

我终于确定了:

    trades = []
    enddate = datetime.date(1900, 1, 1)
    try:
        for startdate in startdates:
            if enddate <= startdate:
                enddate = enddates.next()
                while enddate <= startdate:
                    enddate = enddates.next()
                trades.append((startdate, enddate))
    except StopIteration:
        trades.append((startdate, None))

感谢那些提出问题和回答的人。不知何故,这个小谜题成了我的执念,但我想我终于把这件事做死了,应该继续我的生活。最后真的很简单——令人惊讶的是花了多少工作才把它变得这么简单!

【讨论】:

    【解决方案2】:

    我认为这应该可以获取日期元组,但我不能建议你不使用 for 循环的方式,因为它可能会变得更复杂。

    不过,逻辑非常简单明了。

    result = []
    for startd in start_dates:
        if not result or result[-1][1] is not None and startd>result[-1][1]:
        #can use 'len(result)==0' instead of 'not result'
            for endd in end_dates:
                if endd>startd:
                    result.append((startd,endd))
                    break
            else:
                result.append((start,None))
        if result[-1][1] is None:
            break
    
    result = tuple(result)
    print result
    

    【讨论】:

      【解决方案3】:

      编辑

      这应该与len(start_dates)+len(end_dates) 一起扩展:

      def date_range(start_dates, end_dates):
          result = []
      
          start_i = 0
          end_i = 0
      
          while start_i<len(start_dates):
              while end_i<len(end_dates) and start_dates[start_i]>end_dates[end_i]:
                  end_i += 1
              if end_i == len(end_dates):
                  result.append((start_dates[start_i], None))
                  break
              result.append((start_dates[start_i], end_dates[end_i]))
              while start_i<len(start_dates) and start_dates[start_i]<=end_dates[end_i]:
                  start_i += 1
              end_i += 1
      
          return result
      

      用法:

      In  : start_dates = [
         ....:     datetime.date(2009, 11, 5), datetime.date(2009, 11, 13),
         ....:     datetime.date(2009, 11, 25), datetime.date(2009, 11, 26),
         ....:     datetime.date(2009, 12, 4), datetime.date(2009, 12, 7),
         ....:     datetime.date(2009, 12, 29), datetime.date(2009, 12, 30)]
      
      In : end_dates = [
         ....:     datetime.date(2009, 10, 1), datetime.date(2009, 10, 2),
         ....:     datetime.date(2009, 10, 9), datetime.date(2009, 10, 12),
         ....:     datetime.date(2009, 11, 4), datetime.date(2009, 12, 14),
         ....:     datetime.date(2009, 12, 15)]
      
      In : date_range(start_dates, end_dates)
      Out:
      [(datetime.date(2009, 11, 5), datetime.date(2009, 12, 14)),
       (datetime.date(2009, 12, 29), None)]
      
      In : start_dates = [
         ....:     datetime.date(2009, 11, 5), datetime.date(2009, 11, 13),
         ....:     datetime.date(2009, 11, 25), datetime.date(2009, 11, 26),
         ....:     datetime.date(2009, 12, 4), datetime.date(2009, 12, 7),
         ....:     datetime.date(2009, 12, 29), datetime.date(2009, 12, 30)]
      
      In : end_dates = [
         ....:     datetime.date(2009, 10, 1), datetime.date(2009, 10, 2),
         ....:     datetime.date(2009, 10, 9), datetime.date(2009, 10, 12),
         ....:     datetime.date(2009, 11, 7), datetime.date(2009, 12, 14), # changed (2009, 11, 4) -> (2009, 11, 7)
         ....:     datetime.date(2009, 12, 15)]
      
      In : date_range(start_dates, end_dates)
      Out:
      [(datetime.date(2009, 11, 5), datetime.date(2009, 11, 7)),
       (datetime.date(2009, 11, 13), datetime.date(2009, 12, 14)),
       (datetime.date(2009, 12, 29), None)]
      

      【讨论】:

      • 我想知道,因为我可能误解了问题...如果您将结束日期从2009-11-04 更改为2009-11-07,预期输出是什么?这个答案将导致相同的结果。
      • @JohnMee:已更正。这应该比嵌套的for 循环要好。
      • 打败了我。这就是我在分心编辑问题之前一直在研究的模式……尽管现在我一直在意识到它只是在搜索时交替列表。嗯。
      【解决方案4】:

      这个怎么样。

      all_dates = start_dates.expand(end_dates)
      all_dates.sort()
      
      look_for_start = 1;
      date = []
      start_date = None
      end_date = None
      for i in range(len(all_dates)):
         if look_for_start and all_dates[i] in start_dates:
           start_date = all_dates[i]
           look_for_start = 0;
      
         elsif !look_for_start and all_dates[i] in end_dates:
           end_date = all_dates[1]
           look_for_start = 1;
      
         if start_date == end_date:
           end_date == None
           look_for_start = 0;
      
         if start_date != None and end_date != None;
           date.append((start_date,end_date))
           start_date = None
           end_date = None
      

      在此之后,您将尽可能拥有带有结束日期的 start_dates。只需获取剩余的 start_dates 集并将其结束日期设置为 None

      【讨论】:

      • 列表中没有expand 方法,我认为您的意思是extend。这不会产生所需的输出。
      • 这仍然没有创建所需的输出?
      • 我想我误解了所要求的内容。我认为这应该可以相当有效地解决问题。
      猜你喜欢
      • 2021-08-15
      • 2015-12-23
      • 2019-04-30
      • 2015-06-03
      • 1970-01-01
      • 2013-11-29
      • 2021-12-16
      • 1970-01-01
      • 2020-06-21
      相关资源
      最近更新 更多