2017-12-18 173 views
1

我遇到問題並希望任何人都可以給我一個小技巧來克服它。Python:在迭代時將範圍添加到範圍列表

我有一個2D-python-list(83行和3列)。前兩列是間隔的開始和結束位置。第三列是數字索引(例如:9.68)。該列表按第3列進行反向排序。 我想要得到所有與最高索引不重疊的區間。

這裏是排序列表的示例:

504 789 9.68 
503 784 9.14 
505 791 8.78 
499 798 8.73 
1024 1257 7.52 
1027 1305 7.33 
507 847 5.86 

這裏是我的嘗試:

# Define a function that test if 2 intervals overlap 
def overlap(start1, end1, start2, end2): 
     return not (end1 < start2 or end2 < start1) 

best_list = [] # Create a list that will store the best intervals 
best_list.append([sort[0][0],sort[0][1]]) # Append the first interval of the sorted list 
# Loop through the sorted list 
for line in sort: 
    local_start, local_end = line.rsplit("\s",1)[0].split() 
    for i in range(len(best_list)): 
     best_start = best_list[i][0] 
     best_end = best_list[i][1] 
     test = overlap(int(best_start), int(best_end), int(local_start), int(local_end)) 
     if test is False: 
      best_list.append([local_start, local_end]) 

我也得到:

best_list = [(504, 789),(1024, 1257),(1027, 1305)] 

但我想:

best_list = [(504, 789),(1024, 1257)] 

謝謝!

+0

原始列表是怎樣的?值是字符串嗎?如果是,那麼還沒有列。 –

+0

其實,它們是字符串,這就是爲什麼我需要將它們轉換爲整數來進行測試。這是我用包csv中的csv.reader函數創建的一個列表。 –

+0

所以像這樣:'[['504 789 9.68'],['503 784 9.14'],....]'? –

回答

1

嗯,我有一些關於你的代碼的問題。由於sort包含字符串,因此該行append([sort[0][0],sort[0][1]])做了什麼你期望的?

無論如何,你的問題主要是當你的列表中存在多個元素時,只要其中一個通過重疊測試就可以被添加到列表中(不是你想要的)。例如。當兩個(504, 789),(1024, 1257)都存在時,(1027, 1305)將被插入到列表中,因爲它與(504, 789)進行比較時通過了測試。

於是,我做了一些改變,現在它似乎按預期方式工作:

best_list = [] # Create a list that will store the best intervals 
best_list.append(sort[0].rsplit(" ", 1)[0].split()) # Append the first interval of the sorted list 
# Loop through the sorted list 
for line in sort: 
    local_start, local_end = line.rsplit("\s", 1)[0].split() 
    flag = False # <- flag to check the overall overlapping 
    for i in range(len(best_list)): 
     best_start = best_list[i][0] 
     best_end = best_list[i][1] 
     test = overlap(int(best_start), int(best_end), int(local_start), int(local_end)) 
     print(test) 
     if test: 
      flag = False 
      break 
     flag = True 
    if flag: 
     best_list.append([local_start, local_end]) 

主要思想是檢查每一個元素,如果通過了所有重疊的測試,那麼添加它(的最後一行我的代碼)。之前沒有。

+0

爲什麼使用'enumerate',循環內沒有引用'n'? – godaygo

+0

是的你是對的,它是從調試。我將編輯。 – Eypros

+0

謝謝Eypros,我花了下午的時間在一個具有各種情況的邊界數據集上進行測試,它似乎工作正常! –

0

假設你解析你的CSV和已經與[(start, stop, index), ....][(int, int, float), ...]列表,那麼你可以用下面的排序是:

from operator import itemgetter 
data = sorted(data, key=itemgetter(2), reverse=True) 

這意味着你排序第三的位置,並以相反的順序從返回的結果最大到最小。

def nonoverlap(data): 
    result = [data[0]] 
    for cand in data[1:]: 
     start, stop, _ = cand 
     current_span = range(start, stop+1) 
     for item in result: 
      i, j, _ = item 
      span = range(i, j+1) 
      if (start in span) or (stop in span): 
       break 
      elif (i in current_span) or (j in current_span): 
       break 
     else: 
      result.append(cand) 
    return result 

然後用上面的函數就可以得到想要的結果。對於提供的代碼片段,您將獲得[(504, 789, 9.68), (1024, 1257, 7.52)]。我在這裏使用的事實,你可以使用1 in range(0, 10)這將返回True。雖然這是一個天真的實現,但您可以將其用作起點。如果只想返回開始停止return [i[:2] for i in result]替換返回行。

注意:另外我想補充說,你的代碼有一個邏輯錯誤。您在每次比較後做出決定,但必須在與已經存在於您的所有元素best_list進行比較後做出決定。這就是爲什麼(504, 789)(1027, 1305)通過你的測試,但不應該。我希望這封信會幫助你。

+0

尚未測試,但您能否簡要地向我解釋如何開始,停止和跨度工作?和下劃線對應的是什麼(即:i,j,_ = item)? –

+0

@KMdy由於'item'是一個3元素序列。 'i,j,_ = item'表示你將'i'綁定到'item'中的第一個元素,'j'表示第二個元素,'_'表示第三個元素。 '_'表示佔位符。 Python是一個慣例,如果您對某個值不感興趣,但需要在語法上正確,則將其分配給'_'。 – godaygo