2011-12-11 30 views
2

看看這個csharp代碼,看看你能否告訴我爲什麼在找到並從列表中刪除一個項目後需要退出循環。我們的想法是要經過的鄰居節點的名單,並查看是否有節點n存在那裏,然後刪除鄰居:在foreach循環中刪除一個節點

internal void RemoveDirected(Node n) 
    { 
     foreach (EdgeToNeighbor etn in this.Neighbors) 
     { 
      if (etn.Neighbor.Key == n.Key) 
      { 
       RemoveDirected(etn); 
       break; 
      } 
     } 
    } 

    internal void RemoveDirected(EdgeToNeighbor e) 
    { 
     Neighbors.Remove(e); 
    } 

。 。 。

// Removes EdgeToNeighbor instance from AdjacencyList 
    protected internal virtual void Remove(EdgeToNeighbor e) 
    { 
     base.InnerList.Remove(e); 
    } 

請注意我在第一種方法的RemoveDirected調用後有一個「break」。 我發現如果我在RemoveDirected 後沒有退出,它會在foreach循環中永遠持續下去。我認爲它必須有與foreach工作的方式有關的事情 。如果修改foreach正在處理的列表 ,它會變得混亂並永遠循環。

你見過這種類型的東西嗎?還有什麼其他的選擇可以使用而不是使用break? 當然,我可以將我找到的節點放置在局部變量中,然後從循環中斷開,並將其刪除到循環外。但我在想,可能有更好的方法在csharp中做這個 。

+0

謝謝大家提供您的反饋意見,非常感謝。我希望提出的一個要求是,請爲您提供的解決方案提供代碼。一個代碼示例肯定會讓你更清楚你推薦的內容。提前致謝。 –

回答

0

你可以得到節點的數量,然後在for循環中檢查並從最高到最低刪除,這樣可以避免查找不再存在的項目。

+0

如果您能提供您建議的代碼示例,我將非常感激。 –

+0

@FoRum檢查下文中的competent_tech的答案。 –

8

當您使用迭代器迭代.NET集合時,您不得修改該集合。如果你這樣做,你是在尋求麻煩。

您應該推遲刪除而不是在foreach循環中刪除權限。例如,您可以收集需要在列表中刪除的所有內容,然後在foreach之外將其刪除。

var toDelete = this.Neighbors.Where(etn => etn.Neighbor.Key == n.Key).ToList(); 
foreach (var e in toDelete) { 
    Neighbors.Remove(e); 
} 
+0

這看起來很愚蠢......去哪裏做一個刪除的東西:P〜 – 2011-12-11 04:21:22

+0

@pst爲什麼?這段代碼將意圖傳達給任何閱讀它的人,因爲它幾乎就像純英文一樣。對我來說,這比通過做一些優化工作可能節省的CPU週期要多得多。 – dasblinkenlight

+0

這似乎很愚蠢,因爲Where *是*過濾器。如果還有其他涉及副作用的代碼,那麼是的,有時候我會用這種方法......但不是這樣的情況。(我想我假設鄰居是*不共享*,但這是一個更大的假設,幾乎總是在我的代碼中有效。) – 2011-12-11 04:46:32

1

如果您要移除項目,您絕對不想使用迭代器。一種選擇是將其改變爲向下計數循環:

for (int nI = this.Neighbors.Count; nI >= 0; nI--) 
    { 
     var etn = this.Neighbors[nI]; 
     if (etn.Neighbor.Key == n.Key) 
     { 
      RemoveDirected(n); 
     } 
    } 

你也可以領取鑰匙或項目的環內的集合中刪除,然後一旦您完成迭代執行刪除操作。

但是,如果您只是刪除單個項目並以某種方式鍵入集合中的項目,那麼您實際上不需要任何循環。只需測試集合中密鑰或項目的存在性,如果它存在,只需將其刪除即可。