2016-11-25 107 views
2

我有問題,我無法通過4天。我是蟒蛇noobie。 我正在使用python 2.6的unix box ...並且沒有像numpy,pandas這樣的額外自由度。python從日期範圍中找到唯一日期編號爲

我需要做的是儘可能少的文件行數。所以,當相同的id1,id2的日期範圍中的日期相互覆蓋時,他們需要被覆蓋。但是,正如你所期望的那樣,輸出中的最小值和最大值是不夠的,因爲有些日期不是日復一日。

輸入

ID1|IDTYPE2|20160802|20160912| 
ID1|IDTYPE2|20160803|20160913| 
ID1|IDTYPE2|20160804|20160914| 
ID1|IDTYPE2|20160805|20160915| 
ID1|IDTYPE2|20160808|20160916| 
ID1|IDTYPE2|20160925|20160925| 
ID2|IDTYPE2|20160925|20160925| 

期望輸出

ID1|IDTYPE2|20160802|20160916| 
ID1|IDTYPE2|20160925|20160925| 
ID2|IDTYPE2|20160925|20160925| 

我都試過了,但它gaves我許多成果

f = open(filename, 'rU') 
outf = open(filename + '_date_diff', 'w') 
dict_of_ID_dates = defaultdict(list) 
for line in f: 
    columns = line.split("|") 
    ID1 = (columns[0]) 
    IDType2 = (columns[1]) 
    start = (columns[2]) 
    end = (columns[3]) 
    start_date = datetime.datetime.strptime(start,'%Y%m%d').date() 
    end_date = datetime.datetime.strptime(end,'%Y%m%d').date() 
    diff = end_date - start_date 
    list_of_dates =[] 
    date_ranges = range(diff.days +1) 
    # [0,1,2,3] 
    for date in date_ranges: 
    dates = (start_date + datetime.timedelta(date)).isoformat() 
# [datetime format dates = '20160101'] 
    if dates not in dict_of_ID_dates.values(): 
     dict_of_ID_dates[ID].append(dates) 
print (dict_of_ID_dates) 
+0

文件是巨大的像18個milions行的時候,他們已經拼合和afregaded呈現形式。上面我添加了我卡住的地方。 –

回答

1

假定輸入文件ID和日期總是按升序排列。下面的代碼應該工作。

tmpline充當緩衝區保留行,當ID改變或當前行date1> date2在tmpline緩衝區(意味着我們需要啓動一個新的日期範圍)時追加到輸出。如果緩衝區中當前行中的date2發現大於date2,則緩衝區列2(date2)將被覆蓋。

output = [] 
with open(filename, 'rU') as f: 
    prev_id = None 
    tmpline = '' 
    for line in f: 
     line = line.strip() 
     (id, date1, date2, dummy) = line.rsplit('|', 3) 
     # line = 'ID1|IDTYPE2|20160802|20160912|' 
     # id = 'ID1|IDTYPE2' 
     # date1 = '20160802' 
     # date2 = '20160912' 
     # dummy = '' 

     # append to output when new ID changes or 
     # date1 > previous date2 (start new range of dates) 
     if prev_id != id or date1 > tmpline[2]: 
      if tmpline: 
       output.append('|'.join(tmpline)) 
      tmpline = [id, date1, date2, dummy] 

     # override end date if larger 
     elif date2 > tmpline[2]: 
      tmpline[2] = date2 
     prev_id = id 

    # take care last line 
    tmpline = '|'.join(tmpline) 
    if tmpline != output[-1]: 
     output.append(tmpline) 

輸出中包含的行列表,打印出到控制檯或可寫入另一個文件

# print out the ouput 
for line in output: 
    print line 


# based on the input from the post 
# output = ['ID1|IDTYPE2|20160802|20160916|', 'ID1|IDTYPE2|20160925|20160925|', 'ID2|IDTYPE2|20160925|20160925|'] 
+0

嗨Skycc :)您的解決方案按我的要求工作。但是,正如我在上面爲@Rodolfo解釋的那樣,我只能在家中檢查它。我明天將在工作中嘗試它,並在魯道夫的讚揚下留下更新。週末愉快! –

+0

好的。那麼晚些時候讓我們知道。我的代碼應該適用於python 2和3。編輯一些代碼來照顧最後一行輸入 ID1的 – Skycc

+0

另一部分| IDTYPE2 | 20141208 | 20160606 ID1 | IDTYPE2 | 20141209 | 20160607 ID1 | IDTYPE2 | 20141210 | 20160608 ID1 | IDTYPE2 | 20141211 | 20160609 ID1 | IDTYPE2 | 20141212 | 20160610 ID1 | IDTYPE2 | 20141215 | 20160613 ID1 | IDTYPE2 | 20160603 | 20160603 ID1 | IDTYPE2 | 20160610 | 20160610 ID1 | IDTYPE2 | 20160617 | 20160617 ID1 | IDTYPE2 | 20160624 | 20160624 ID1 | IDTYPE2 | 20160701 | 20160701 您的代碼輸出 AAVL | SHSO | 20141208 | 20160606 AAVL | SHSO | 20160701 | 20160701 預期輸出 ID1 | IDTYPE2 | 20141208 | 20160613 ID1 | IDTYPE2 | 20160617 | 20160617 ID1 | IDTYPE2 | 20160624 | 20160624 ID1 | IDTYPE2 | 20160701 | 20160701 –

0

有關的日期格式,你是很酷的事情使用是你甚至不需要將它轉換爲字符串以外的任何東西。

它使它更容易,因爲你可以簡單地說date1 > date2和字符串比較對他們有效!

說了這麼多,你可以這樣做:

f = open(filename, 'rU') 
ranges = {} 
for line in f: 
    elem = line.split("|") # get every item of the row in a list 

    if elem[0] not in ranges: 
     ranges[elem[0]] = [] 

    matched = False 
    for x in ranges[elem[0]]: # check the current line overlap with any previous ones 
     if elem[2] >= x[1] and elem[2] <= x[2] or \ 
      elem[3] >= x[1] and elem[3] <= x[2] or \ 
      elem[2] <= x[1] and elem[3] >= x[2] or \ 
      elem[2] >= x[1] and elem[3] <= x[2]: 
      x[1] = min(elem[2], x[1]) # modify the date range 
      x[2] = min(elem[3], x[2]) 
      matched = True 
      break 

    if not matched: # if it does not overlap add it. 
     ranges[elem[0]].append([elem[1], elem[2], elem[3]]) 

# This is just for display purposes 
for key in ranges.iterkeys(): 
    for v in ranges[key]: 
     print key + '|' + v[0] + '|' + v[1] + '|' + v[2] + '|' 

一些你可能想,雖然考慮的是你是否需要該行以特定的順序,如果你需要使用比其他的東西字典來存儲範圍。

+0

順便說一句,我無法在Python 2.6中測試它,讓我知道它是否有效。 – Rodolfo

+1

嗨Rodolfo :)我已經鎖定了我的想法如此糟糕的解決方案,將比較日期範圍,我不會經過它沒有幫助:)你的解決方案,我的要求。感謝那!不幸的是,我只能在家中檢查,我有其他版本的Python,而不是在工作中。我會在星期一檢查它,並讓你知道它是如何發生的。再次感謝! –