Reputation: 10364
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.
The structure is something similar to:
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;}
}
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));
I need a List<A>
of every record which:
1.) No longer has a recId
held in the CollectionB
.
OR
2.) No longer has a record which has a matching recId
and category
in CollectionB
For example it is possible that within CollectionA
there are 2 records with the same recId
but different category
.
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.
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.
edit: input/result
CollectionA
1,2254,Category A
2,2236,Category A
3,2415,Category B
4,1275,Category B <--- same person as below, diff category
5,1275,Category C <--- same person as above, diff category
CollectionB
2254,Category A
2415,Category B
1275,Category C
Expected Result
I would expect (from CollectionA) the following id's to be highlighted in my list for deletion: 2, 4
Upvotes: 1
Views: 2872
Reputation: 8892
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));
OLD ANSWER
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 ;
}
Then just call Except method and pass your comparer
:
var resultList = CollectionA .Except(CollectionB, new MyEqualityComparer());
Or if you implement it on your class, instead of a separate comparer
you can just call Except
:
var resultList = CollectionA .Except(CollectionB);
Be aware that you need also implement GetHashCode
method.
UPDATE
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});
And then create your 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();
}
}
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 ());
But I think you should go with the simple Where
filter as creating new List of A
type can cause lot of performance overhade.
Upvotes: 2
Reputation: 460098
You can always use set methods like Enumerable.Except
and use another set method Join
to get the complete data.
I need a
List<A>
of every record which: 1.) No longer has arecId
held in theCollectionB
.
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.) No longer has a record which has a matching
recId
andcategory
inCollectionB
Maybe:
var canBeRemovedFromA = CollectionA
.Where(a => CollectionB.Any(b => a.recID == b.recId && a.category!= b.category));
this doesn't check if there is at least one matching category. It's not clear if that's a must.
Upvotes: 1