2012-04-06 83 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)); 
相关问题