2012-04-06 71 views
1

如何實現LINQ從一個類型爲A的對象集合中提取Guid,以便它們可以從另一個類型爲B的對象集合中排除這些Guid。對象A和對象B兩者都具有被稱爲「ID GUID字段「LINQ來選擇不同類型的集合中的項目

我有以下:

  1. ObservableCollection<Component> component元器件具有 字段稱爲Guid類型的ID
  2. ObservableCollection<ComponentInformation> ComponentInformationCollection ComponentInformation 有一個名爲類型的ID領域Guid

我的實現:

component => 
{ 
    if (component != null) 
    { 
     var cancelledComponents = new List<ComponentInformation>(); 
     foreach (Component comp in component) 
     { 
      cancelledComponents.Add(new ComponentInformation() { ID = comp.ID }); 
     } 
     this.ComponentInformationCollection.Remove(cancelledComponents); 
    } 
}); 

我相信有一個更優雅的解決方案,我在一直在努力解決,但我一直運行到是問題創建一個'新的ComponentInformation',這樣的類型不會給我一個錯誤。

======最終解決=======

var cancelledComponentIDs = new HashSet<Guid>(component.Select(x => x.ID)); 
this.ComponentInformationCollection.Remove(
    this.ComponentInformationCollection.Where(x => cancelledComponentIDs.Contains(x.ID)).ToList()); 

謝謝: 傑森 - 我用這個作爲一個模板,我的最終解決方案(見下表)。 Servy - 雖然我可以使用比較器,但我認爲對於這種特殊情況,比較器並不是必需的,因爲它是一次性使用的情況。

ComponentInformationCollection是Silverlight DependencyProperty,它會在更改時觸發INotifyChangedEvent(MVVM模式),所以上述解決方案對我的情況最有效。

回答

4

我這樣做:

var ids = new HashSet<Guid>(
       component.Select(x => x.ID) 
     ); 
var keepers = ComponentInformationCollection.Where(x => !ids.Contains(x.ID)); 
+0

這是很多工作,只是沒有定義'IEqualityComparer'的'組件'。你做了兩個額外的投影,一個額外的地方,你需要把所有東西都放到HashSet中(意味着沒有流式傳輸)。 – Servy 2012-04-06 01:42:22

+0

我認爲你也有收集倒退,如果我正在閱讀正確的問題,他想從ComponentInformationCollection丟棄... – 2012-04-06 01:49:31

+0

@Servy:我認爲你錯過了這一點。 – jason 2012-04-06 02:02:35

0

想大聲(意思是我沒有創建一個項目,類型和編譯此),但如何:

var cancelledComponents = component.Select(c=> new ComponentInformation() {ID = c.ID}).ToList(); 
cancelledComponents.ForEach(c => ComponentInformationCollection.Remove(c)); 
+0

如果對象實現IEquatable或類似的,這將工作。否則ComponentInformation的新實例將不會等於原始集合中的實例。 – 2012-04-06 01:41:42

1

如果沒有按Component」 t已經定義了使用ID進行比較的Equals和GetHashCode,您可以定義比較器,例如:

class ComponentComparer : IEqualityComparer<Component> 
{ 
    public int Compare(Component a, Component b) 
    { 
    return a.ID.CompareTo(b.ID); 
    } 

    public int GetHashCode(Component a) 
    { 
    return a.ID.GetHashCode(); 
    } 
} 

然後,你可以使用:

var result = componentCollectionA.Except(componentCollectionB, new ComponentComparer()); 

(註銷我的頭頂部;可能需要稍作修改才能編譯。)

+0

不,這兩個集合中的類型是不同的。這就是整個觀點,爲什麼你不能只用'Except'。 – jason 2012-04-06 01:59:24

0

有很多方法可以解決這個問題...這是一個非常簡單的Linq語句,用於查詢您要從集合中查找的語句。

var keep = typeAList.Where(a => typeBList.FirstOrDefault(b => a.ID == b.ID) == null); 

這裏是我放在一起演示它的小測試應用程序。

+0

這是接近最大限度地低效率,而仍然是一個合理的實施。當你的意思是「任何」時,不要使用「計數」,並且不要通過建立一個可以非常快速地檢查遏制的集合來更有效地重複線性掃描集合。 – jason 2012-04-06 02:06:12

+0

在計數聲明上的良好呼叫...我更新並刪除了第二次完整掃描。 – 2012-04-06 03:20:41

1

LINQ將允許你找到你需要的GUID,但是LINQ序列通常是不可變的;您仍然需要使用某種循環來實際更改集合。訣竅是獲取要刪除的原始集合的正確實例。

實現其中一個相等/比較接口是一種方法,如果您需要在多個地方比較您的對象以實現相等性,絕對是一種可行的方法。如果你不想這樣做,這應該得到你想要的:

var removeme = (from x in this.ComponentInformationCollection 
       join y in component on x.ID equals y.ID 
       select x).ToList(); 
removeme.ForEach(x => this.ComponentInformationCollection.Remove(x));