2012-08-24 60 views
3

我有开始日期列表和结束日期列表。他们被分类...如何将两个日期列表合并为一系列日期间隔?

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_date开始一个句点,一个end_date结束句点。时间段不能重叠:每个周期必须在下一个开始之前结束,也不能从最后一个结束的那一天开始。如果最后有一个start_date没有合适的end_date匹配,则使用None作为最终结束日期。

因此,输入上面的生成:

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

我使用for循环中的for循环,不知道如果没有更好的办法。性能很受关注,因为它将应用于40年的数千场景;一些列表涉及数千个日期。

X ----

说实话,我很惊讶的人有这么多的麻烦了解的问题......我会揭示应用再试一次,也许抽象使其难以可视化...

开始日期表示我们收到建议购买股票的日期。结束日期是我们收到卖出建议的日期。建议的来源不同,我们正在测试如果我们使用来自一个来源的购买建议,但来自另一来源的推荐建议会发生什么。因此,我们有两个日期序列,我们想要将这些日期序列分解成两个或两个以上的时间间隔,我们可以在这些日期中对股票持仓。

因此,我们从start_dates购买股票的日期。所以在11月5日我们买入一个头寸。现在我们通过end_dates工作寻找什么时候我们会首先被告知出售它 - 12月14日。现在重复等待买入建议,然后是卖出建议。因此,您可以交替列表以获得日期对的逻辑序列。如果最后我们持有一个未平仓头寸,我们注意到通过使用None或提供一个特殊日期关闭。

+1

结果如何达到您想要达到的效果。它很难说只是从这个问题你怎么想这将变成 –

+0

@PabloKarlsson我相信所期望的结果已经在问题中指定?!这是一个日期元组列表。 –

+0

是的,但我如何映射它们(start_dates [1],end_dates [1])? –

回答

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)) 

感谢那些谁问的问题和回答。因为没有理性的原因,这个小小的谜题对我来说成了一个固定的东西,但我终于认为我已经完成了这件事,并且应该继续我的生活。这真的非常简单 - 惊人的多少工作才能使它变得如此简单!

0

这个怎么样。

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的,并得到他们的结束日期设置为无

+0

列表中没有'expand'方法,我认为你的意思是'extend'。而这不会产生所需的输出。 – sberry

+0

感谢我使用众多的语言困惑.. –

+0

虽然这仍然不会创建所需的输出? – sberry

2

编辑

这应该与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)] 
+0

不错。尽管我仍然试图琢磨它是如何工作的。 –

+0

我想知道,因为我可能误解了这个问题......如果你将结束日期从'2009-11-04'更改为'2009-11-07',预期输出是什么?这个答案会导致相同的结果。 – sberry

+0

这是正确的。答案不会改变。 –

1

我想这应该工作得到日期元组,但我不能建议你的方式,而不使用循环,因为它可能会得到莫反而变得复杂。

虽然这个逻辑非常简单明了。

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 
相关问题