使用除多个属性之外的内容过滤列表

时间:2015-02-27 13:16:13

标签: c# linq

我正在尝试编写一个方法,最终会给我一组记录,这些记录在我引用的不同集合中不再有相应的记录。

结构类似于:

public class A
{
    int id {get; set;}
    int recId {get; set;}
    string category {get; set;}
}


public class B
{
    int recId {get; set;}
    string category {get; set;}
}

到目前为止,我有以下一点LINQ给我收集了丢失的记录,但这只给了我任何遗漏的recId

var noLongerHaveRecordInCollectionB =
CollectionA.Select(x => x.recId).Except(CollectionB.Select(x => x.recId));

我需要List<A>的每条记录:

1。)recId中不再有CollectionB

OR

2.。)recId

中不再有匹配categoryCollectionB的记录

对于示例,有可能在CollectionA内有2条记录具有相同的recIdcategory不同。

如果CollectionB现在只包含recId的1条记录,我会删除CollectionA中没有相应类别的记录。

所以最终的问题是如何将noLongerHaveRecordInCollectionB填入已经针对<T>检查过的所有CollectionB A而不仅仅是recId目前所做的,{I}}想要整个对象。

编辑:输入/结果

CollectionA

1,2254,A类

2,2236,A类

3,2415,B类

4,1275,B类&lt; ---同一人如下,差异类别

5,1275,C类&lt; ---与上述相同的人,差异类别

CollectionB

2254,A类

2415,B类

1275,C类

预期结果

我希望(来自CollectionA)在我的列表中突出显示以下id以供删除:2,4

2 个答案:

答案 0 :(得分:2)

您可以使用带有Where条件的||子句来简单地实现所需内容。无需寻求复杂的解决方案。

 var result = collectionA.Where(a => collectionB.Any(b => a.recId == b.recId && a.Category != b.Category)
              || !collectionB.Any(b => b.recId == a.recId));

OLD ANSWER

您可以为您的类实现IEqualityComparer,并根据您感兴趣的字段比较对象。例如,实现Equals方法,如下所示:

public bool Equals(A a, B b)
{
    return a.recId  == b.recId && a.category == b.category ;
}

然后只需调用Except方法并传递comparer

var resultList = CollectionA .Except(CollectionB, new MyEqualityComparer());

或者如果您在课堂上实施,而不是单独的comparer,则可以致电Except

var resultList = CollectionA .Except(CollectionB);

请注意,您还需要实施GetHashCode方法。

<强>更新

如果您想使用IEqualityComparer<T>,可以从第二个列表中创建一个新列表:

  var secondListA = CollectionB.Select(x=> new A(){Category=x.Category, recId=x.recId});

然后创建您的Comparer

sealed class MyComparer : IEqualityComparer<A>
{
    public bool Equals(A x, A y)
    {
        if (x == null)
            return y == null;
        else if (y == null)
            return false;
        else
            return x.recId== y.recId&& x.Category == y.Category;
    }

    public int GetHashCode(A obj)
    {
        return obj.recId.GetHashCode();
    }
}

使用Except()重载,通过使用指定的IEqualityComparer<T>比较值来产生两个序列的集合差异。:

    var result = CollectionA.Except(secondListA, new MyComparer ());

但我认为你应该使用简单的Where过滤器,因为创建A类型的新列表会导致大量的性能改变。

答案 1 :(得分:1)

您始终可以使用Enumerable.Except等设置方法,并使用其他方法Join来获取完整数据。

  

我需要List<A>的每条记录:   1.)recId中不再有CollectionB

var onlyInA = CollectionA.Select(x => x.recId).Except(CollectionB.Select(x => x.recId));
var dataOnlyInA = from a in CollectionA
                  join recId in onlyInA 
                  on a.onlyInA equals recId 
                  select a;
List<A> result =  dataOnlyInA.ToList();
  

2.。)recId

中不再有匹配categoryCollectionB的记录

也许:

var canBeRemovedFromA = CollectionA
    .Where(a => CollectionB.Any(b => a.recID == b.recId && a.category!= b.category));

这不会检查是否至少有一个匹配的类别。目前尚不清楚这是否必须。