使用多个属性上的except过滤列表 [英] Filtering a list using except on multiple properties
问题描述
我正在尝试编写一种方法,该方法最终将给我一个记录集合,而这些记录在我要引用的另一个集合中不再具有相应的记录.
I am trying to write a method which will ultimately give me a collection of records which no longer have a corresponding record within a different collection to which I am referencing.
结构类似于:
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
:
So far I have the following bit of LINQ to give me my collection of missing records but this only giving me any recId
that is missing:
var noLongerHaveRecordInCollectionB =
CollectionA.Select(x => x.recId).Except(CollectionB.Select(x => x.recId));
我需要每条记录的List<A>
:
1.)CollectionB
中不再保存recId
.
OR
2.)不再具有CollectionB
对于示例,CollectionA
中可能有2条记录具有相同的recId
但不同的category
.
For example it is possible that within CollectionA
there are 2 records with the same recId
but different category
.
如果CollectionB
现在仅包含该recId
的1条记录,我想删除CollectionA
中没有相应类别的记录.
If CollectionB
now only contains 1 record for that recId
I would want to remove the record in CollectionA
which does not have the corresponding category.
所以最终的问题是,如何用已经针对CollectionB
检查过的所有<T>
A填充noLongerHaveRecordInCollectionB
,而不仅仅是像现在这样的recId
,我想要整个对象.
So the ultimate question is how can I populate noLongerHaveRecordInCollectionB
with all <T>
A's that have been checked against CollectionB
and not just the recId
as it currently does, I want the whole object.
修改:输入/结果
CollectionA
1,2254,类别A
1,2254,Category A
2,2236,类别A
2,2236,Category A
3,2415,类别B
3,2415,Category B
4,1275,类别B< ---与下面相同的人,比较类别
4,1275,Category B <--- same person as below, diff category
5,1275,类别C< ---与上述相同,差异类别
5,1275,Category C <--- same person as above, diff category
CollectionB
2254,类别A
2415,类别B
1275,类别C
预期结果
我希望(来自CollectionA)以下ID在我的列表中突出显示以删除:2,4
I would expect (from CollectionA) the following id's to be highlighted in my list for deletion: 2, 4
推荐答案
使用带有||
条件的Where
子句,您可以简单地实现所需的内容.无需寻求复杂的解决方案.
You can simply achive what you want by using Where
clause with ||
condition. No need to go for the complex solution.
var result = collectionA.Where(a => collectionB.Any(b => a.recId == b.recId && a.Category != b.Category)
|| !collectionB.Any(b => b.recId == a.recId));
旧答案
您可以为 IEqualityComparer 实现您的课程并根据您感兴趣的字段比较对象.例如,实现Equals方法,如下所示:
You can implement IEqualityComparer for your class and compare the objects based on the fields you are interested in.For example implement the Equals method like this:
public bool Equals(A a, B b)
{
return a.recId == b.recId && a.category == b.category ;
}
然后只需调用Except方法并传递您的comparer
:
Then just call Except method and pass your comparer
:
var resultList = CollectionA .Except(CollectionB, new MyEqualityComparer());
或者,如果您在类上实现它,而不是单独的comparer
,则只需调用Except
:
Or if you implement it on your class, instead of a separate comparer
you can just call Except
:
var resultList = CollectionA .Except(CollectionB);
请注意,您还需要实现GetHashCode
方法.
Be aware that you need also implement GetHashCode
method.
更新
如果要使用IEqualityComparer<T>
,则可以从第二个列表中创建一个新列表:
If you want to go with the IEqualityComparer<T>
you can create a new List from the second list:
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>
比较值来产生两个序列的集合差.:
And use Except()
overload which produces the set difference of two sequences by using the specified IEqualityComparer<T>
to compare values.:
var result = CollectionA.Except(secondListA, new MyComparer ());
但是我认为您应该使用简单的Where
过滤器,因为创建新的A
类型列表可能会导致很多性能过高.
But I think you should go with the simple Where
filter as creating new List of A
type can cause lot of performance overhade.
这篇关于使用多个属性上的except过滤列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!