2010-04-23 57 views
3

我的問題是枚舉器從SortedList中刪除項目是否安全?在迭代過程中從SortedList中刪除是否安全

SortedList<decimal, string> myDictionary; 
// omitted code 

IEnumerator<decimal, string> enum = myDictionary.GetEnumerator(); 

while(enum.MoveNext) 
{ 
    // is it ok to remove here? 
    myDictionary.Remove(enum.Current.Key); 
} 
+3

不可以,你應該得到一個InvalidOperationExcpetion – bitbonk 2010-04-23 12:37:28

+1

您還需要重命名變量'enum'是'@ enum'爲'enum'是一個保留字。 – James 2010-04-23 12:48:34

+2

是的,它是完全安全的,因爲它不會工作:)請考慮查詢您的收藏以獲取要刪除的項目(例如LINQ) – 2010-04-23 12:57:13

回答

8

這將引發異常 - 您不能在迭代它的同時修改集合。

如果你仔細想一想,你會明白爲什麼。如果允許從集合中添加或刪除,則不會再遍歷相同的集合 - 您要麼添加了太多(添加),要麼沒有足夠的項目(刪除)。

+0

如果您可以解釋爲什麼不應該允許這樣做,可以給予獎勵積分。 – 2010-04-23 12:42:21

+0

這裏你去:「索引序列是基於排序順序。當添加一個元素時,它會以正確的排序順序插入到SortedList中,並且索引會相應地進行調整。當元素被移除時,索引也會相應地進行調整。因此,特定鍵/值對的索引可能會隨着元素從SortedList對象中添加或刪除而發生變化。「MSDN,鏈接列表文檔 – 2010-04-23 12:53:22

+1

我在想STL迭代器,其中一些可以安全地刪除,有些不是 – 2010-04-23 12:59:29

2

通常不支持迭代過程中的列表操作。預期的行爲是拋出一個異常,但即使一個集合沒有做到這一點,你也不能依賴這個工作。

您可以先將元素複製到另一個列表中,然後遍歷這個要修改的新項目列表。

2

否。拋出InvalidOperationExcpetion。我同意已經列舉的項目可能是可刪除的,因爲有一個固定的索引。但是,問題如下:

SortedList的實現不夠聰明,無法確定刪除對進一步執行可枚舉沒有任何影響。爲了保持簡單和表現良好,它不應該。

4

如前所述,您期望做的事是不可能的。但是,另一種解決方案是簡單地維護標記爲刪除的項目列表,然後刪除這些後續字詞。我也會選擇foreach而不是while循環,代碼較少,例如,

var removeList = new List<decimal>(); 
foreach (var item in myDictionary) 
{ 
    // have a condition which indicates which items are to be removed 
    if (item.Key > 1) 
    { 
     removeList.Add(item.Key); 
    } 
} 

或者,如果你只是想找回刪除的項目,使用LINQ

var removeList = myDictionary.Where(pair => pair.Key > 1).Select(k => k.Key).ToList(); 

然後,只需從列表中刪除。

// remove from the main collection 
foreach (var key in removeList) 
{ 
    myDictionary.Remove(key); 
} 
+2

你確定你的第二個例子會工作嗎?我沒有嘗試過,但你的'removeList'只是一個查詢,並且還會在列表中重複*,導致與之前一樣的異常,我想你需要添加一個'.ToList()'或'.ToArray()'來獲得一個新的,所以你可以更改你的原始列表 – Oliver 2010-04-26 06:27:52

+0

@Oliver:+1好的地方,我從來沒有測試過自己也會更新 – James 2010-04-26 07:54:21

2

正如其他人已經指出它不會工作。但是,由於集合是一個SortedList,因此可以使用RemoveAt方法。

該方法有一個稍好一點的內存配置文件,因爲它不需要額外的開銷,而使用單獨的列表來跟蹤刪除操作的O(n)增加。與O(n^2 * log(n))相比,它也將具有O(n^2)性能概況。 RemoveAt方法是O(n),因爲它必須執行數組複製。 Remove方法在內部調用RemoveAt之前添加一個O(log(n))操作來查找索引。所有這些可能都不關心你,但是如果你遇到涉及很多'n'的情況,這很有用。

var myDictionary = new SortedList<decimal, string>(); 

// omitted code 

int i = 0; 
while (myDictionary.Count > 0 && i < myDictionary.Count) 
{ 
    if (/* predicate to use for removal */) 
    { 
    myDictionary.RemoveAt(i); 
    } 
    else 
    { 
    i++; 
    } 
} 
+0

不錯!如果你想在'if'中檢查元素'i',你可以使用' myDictionary.Values [i]',作爲下面的列表排序。 – v01pe 2016-02-17 09:45:24

0

另一個解決方法:

  int counter= MyDictionary.Count; 
      if (counter == 0) 
       return; 

      for (int i = 0; i < counter;i++) 
      { 
       KeyValuePair<MyIdentifier, MyValue> key = (KeyValuePair<MyIdentifier, MyValue>)MyDictionary.ToArray()[i]; 
       MyIdentifier identifier = null; 

       if (key.Key != null) 
        identifier = key.Key as MyIdentifier; 

       if (identifier != null) 
        if (MyCondition) 
        { 
         MyDictionary.Remove(identifier); 
         counter--; 
        } 
      } 
相關問題