2011-11-01 43 views
1

我想迭代一個項目集合,執行一個操作,然後刪除當前索引處的項目。迭代集合並修改它的最佳實踐?

的方式我有這個目前實行的是像這樣:

foreach (CormantRadPane pane in GetPanes().ToList()) 
{ 
    pane.Clear(); 
    StateManager.Remove(pane); 
    LayoutManager.Instance.RegisteredPanes.Remove(pane); 
    Items.Remove(pane); 
} 

通過調用ToList我創建集合的副本,但保持第一集合中的每個對象的引用。這使我可以迭代GetPanes的收集返回,而不用'技術上'修改集合。

這顯然很容易發現一些嚴重難以追查的錯誤。以乾淨的方式執行此類邏輯的標準方式是什麼,但是對於正在發生的事情的複雜性也更加清楚。

我做了一些環顧四周,看到使用for循環和向後遍歷列表的東西,但看起來很龐大。我的感覺與保留第二個「刪除」項目列表相同,然後在第一個循環完成後遍歷該列表,刪除第二個列表中找到的每個對象。

你如何處理它?謝謝。

+0

可能的重複[如何修改或刪除可枚舉集合中的項目,而在C#中迭代它](http://stackoverflow.com/questions/308466/how-to-modify-or-delete-items-from -an-enumerable-collection-while-iterating-thro) –

+0

@Tuzo我看到這篇文章,並提到我的想法提供的解決方案。被接受的解決方案的第一個評論說,解決方案是有缺陷的,然後它是固定的,然後人們有更好的方法來做其他幾個想法。國際海事組織仍然需要進行一些討論。 –

回答

5

代替目前的做法,你可以創建一個變量,並使用它,我建議使用for迴路窗格中去除,招只是重複它是反向:

var panes = GetPanes(); 
int count = panes.Count; 
for(int i= count - 1; i>=0; i--) 
{ 
     pane = panes[i]; 
     pane.Clear(); 
     StateManager.Remove(pane); 
     LayoutManager.Instance.RegisteredPanes.Remove(pane); 
     //Items.Remove(pane); 
     Items.RemoveAt(i); 
} 

調用Items.Remove(pane);需要O(N)(如果是列表),但在使用Items.RemoveAt(i);的情況下,它需要O(1),因此,您當前的方法需要O(n^2),但是如果您可以調用RemoveAt(索引)(您有一些列表並且它們以相同的方式排序)你可以在O(n)中處理它。

+0

通過索引訪問項目是去這裏的方式 –

+0

我不相信我的當​​前代碼每次迭代通過集合時都會創建一個新列表。如果確實如此,那麼我肯定會學到一些東西,但我的理解是,它會創建一個集合的副本,但會保留對第一個集合中對象的引用。我怎麼測試這個? –

+0

@Sean Anderson你是對的我編輯過,但這種方式是處理這個問題的常用方法,因爲我看到類似的問題,有一種醜陋的方式被接受爲答案,這裏有一種正常的方式,你可以做很多事情,但每個開發人員都知道這段代碼的含義,並且維護更容易。 –

0

您可以使用LINQ列表擴展名,如:

List<Item> items = GetItems(); items.ForEach(i => {i.DoStuff();i.DoStuff2(););}

至少這是我通常做的。

+0

我相信這是我的代碼目前所做的。我在我的foreach循環的聲明中調用ToList(),它應該與您的items對象相同。然後,我遍歷項目對象。只是更緊湊一點。 –

0

你所指的是Robust Iterator,但我不認爲在C#和Java中提供的迭代器都是健壯的。

如果您只想通過List進行穩健迭代,則可以通過跟蹤列表的索引來實現自己的Robust Iterator。這對於定義較少的集合以及某些非隨機訪問迭代(如數據庫結果集)可能無效。

也許另一個回答者可以幫助您找到一種方法,在特定情況下不需要強大的迭代器。