2012-03-31 125 views
1

我有以下代碼從集合中刪除組。從技術上講,不應該有重複,但它確實會刪除所有。任何與LINQ到.Remove.Where..的技巧?從ObservableCollection中刪除KeyValue最有效的方法是什麼?

public void DeleteGroup(KeyValuePair<int, string> group) 
      { 
       while (this.Groups.Any(g => g.Key.Equals(group.Key))) 
       { 
        var groupToRemove = this.Groups.First(g => g.Key.Equals(group.Key)); 
        this.Groups.Remove(groupToRemove); 
       } 

      } 
+0

你可以試試[這](http://stackoverflow.com/a/1637448/884410),只需使用鍵,而不是價值 – 2012-03-31 01:00:19

回答

2

假設你傳遞一個KeyValuePair使用相同的密鑰和相同的價值,這是與ObseravableCollection的最有效的方式。

public void DeleteGroup2(KeyValuePair<int, string> group) 
{ 
    Groups.Remove(group); 
} 

此操作,因爲一個KeyValuePair是一個結構,並且當重載運算符==施加其比較兩個密鑰和該結構的數值數據成員。

同樣,如果你在包含在該組obserabableCollection ......如果值不匹配,它不會工作完全相同的Key和Value通過這會工作得很好。

幕後的ObserableCollection是相當多的列表,以便它必須執行==操作符的每個項目迭代。您發佈的代碼也是如此。僅僅因爲它使用LINQ並不意味着它更高效。這不像LINQ where子句使用任何索引,就像LINQ to SQL一樣。

public void DeleteGroup3(KeyValuePair<int, string> groupToDelete) 
{ 
    var itemsToDelete = 
     (
      from g in Groups 
      where g.Key == groupToDelete.Key 
      select g 
     ); 

    foreach (var kv in itemsToDelete) 
    { 
     Groups.Remove(kv); 
    } 
} 

這很可能是最有效的使用LINQ如果你要保證你刪除所有項目,即使那些有重複鍵的方法。

public void DeleteGroup4(KeyValuePair<int, string> group) 
{ 
    List<int> keyIndexes = new List<int>(); 
    int maxIndex = Groups.Count; 
    for (int i = 0; i < maxIndex; i++) 
    { 
     if (Groups[i].Key == group.Key) 
     { 
      keyIndexes.Add(i); 
     } 
    } 

    int indexOffset = 0; 
    foreach (int index in keyIndexes) 
    { 
     Groups.RemoveAt(index - indexOffset); 
     indexOffset++; 
    } 
} 

此,如果你有相同的密鑰多個項目應具有所有這些性能最好的,或者你不知道確切的相同鍵值對作爲原始。

我相信你DeleteGroup方法是2N^2的大O ... N的外任何while循環和N爲第一和N爲刪除。就拿外環時代裏面的​​總和,你會得到2N^2

DeleteGroup2是N大O和有所有這些的最佳性能。缺點是你需要知道密鑰和價值,而不僅僅是密鑰。它也只會刪除找到的第一個項目。它不會刪除具有相同密鑰和相同值的重複項目。

DeleteGroup3 IS的N + N^2大O。 N爲選擇。更糟糕的情況是,你的密鑰在那裏N次,所以N^2的刪除。

DeleteGroup4是2N的大O。 N來查找索引,並且在最壞的情況下,如果所有項目具有相同的密鑰,那麼它的N將刪除它們中的每一個,因爲RemoveAtIndex是1的大O.如果只知道密鑰並且您擁有具有相同密鑰的多個項目的可能性。

如果你知道一個事實,你不會有重複的項目,我會用DeleteGroup2。如果您有重複的可能性,DeleteGroup4應具有最佳性能。

在附註中,如果不會有重複項,並且您不一定知道Key和Value,則仍然可以使用DeleteGroup2的最佳性能選項,但會創建一個名爲KeyValueIntString並具有Key和Value屬性的類。然後覆蓋IsEquals方法,以便它只比較Key屬性,而不是比較Key和Value數據成員的KeyValue結構。然後,您可以使用ObserableCollection.Remove方法,而不必擔心知道存儲的值。 I.E.你可以傳遞一個KeyValueIntString的實例,該KeyValueIntString有Key集,但你不必擔心設置Value屬性。

評論後,我決定添加最好的可讀性方法,儘管它的性能更差。擁有N^4的大O. N表示選擇,N表示ToList,N表示ForEach,N表示刪除。

public void DeleteGroup5(KeyValuePair<int, string> groupToDelete) 
{ 
    (
     from g in Groups 
     where g.Key == groupToDelete.Key 
     select g 
    ).ToList().ForEach(g => Groups.Remove(g)); 
} 
+0

哇!這樣的答案。我正在尋找更短的解決方案 - 確保LINQ使用迭代。這關乎可讀性/可維護性。我的收藏幾乎不會有超過1-2件物品,刪除操作幾乎永遠不會被稱爲:)我只是想寫它最短,最乾淨的方式。 DeleteGroup2應該可以工作! – katit 2012-03-31 02:31:00

+0

在1-2項目的情況下,我會去爲了可讀性。如果你有1000或更多的項目,我會去表演。在很多代碼評論過程中,我看到LINQ的使用僅僅是因爲它很酷且新,並且導致性能非常差,除非您知道在應用或不應用延遲加載時它是如何工作的。例如,在整個表上使用LINQ 2 SQL並在代碼中應用where子句時,使用ToList方法會導致可怕的性能,因爲主鍵,索引和外鍵不被使用。所有的比較都是在客戶端或Web服務端完成的。無論如何,我的2美分。 – 2012-03-31 03:33:42

+0

關於使用LINQ時的可讀性與性能。你只需要知道如何以及何時應用它。 – 2012-03-31 03:34:24

相關問題