Exclude items of one list in another with different object data types, LINQ?
Solution 1
Instead of creating new objects, how about checking the properties as part of the linq query
List<Human> humans = _unitOfWork.GetHumans();
List<AnotherHuman> anotherHumans = _unitofWork.GetAnotherHumans();
// Get all anotherHumans where the record does not exist in humans
var result = anotherHumans
.Where(ah => !humans.Any(h => h.LastName == ah.LastName
&& h.Name == ah.Name
&& h.Birthday == ah.Birthday
&& (!h.PersonalId.HasValue || h.PersonalId == ah.PersonalId)))
.ToList();
Solution 2
var duplicates = from h in humans
from a in anotherHumans
where (h.PersonalID == a.PersonalID) ||
(h.LastName == a.LastName &&
h.FirstName == a.FirstName &&
h.Birthday == a.Birthday)
select a;
anotherHumans = anotherHumans.Except(duplicates);
Solution 3
var nonIdItems = anotherHumans
.Where(ah => !ah.PersonalID.HasValue)
.Join(humans,
ah => new{ah.LastName,
ah.FirstName,
ah.Birthday},
h => new{h.LastName,
h.FirstName,
h.Birthday},
(ah,h) => ah);
var idItems = anotherHumans
.Where(ah => ah.PersonalID.HasValue)
.Join(humans,
ah => ah.PersonalID
h => h.PersonalID,
(ah,h) => ah);
var allAnotherHumansWithMatchingHumans = nonIdItems.Concat(idItems);
var allAnotherHumansWithoutMatchingHumans =
anotherHumans.Except(allAnotherHumansWithMatchingHumans);
Gyuzal R
Updated on October 24, 2020Comments
-
Gyuzal R over 3 years
I have two lists filled with their own data. lets say there are two models
Human
andAnotherHuman
. Each model contains different fields, however they have some common fields likeLastName, FirstName, Birthday, PersonalID
.List<Human> humans = _unitOfWork.GetHumans(); List<AnotherHuman> anotherHumans = _unitofWork.GetAnotherHumans();
I would like to exclude the items from list
anotherHumans
whereLastName, FirstName, Birthday
are all equal to the corresponding fields of any item in listhumans
.However if any item in
anotherHumans
list hasPersonalID
and item in listhumans
have the samePersonalID
, then it is enough to compareHuman
withAnotherHuman
only by thisPersonalID
, otherwise byLastName, FirstName and Birthday
.I tried to create new list of dublicates and exclude it from
anotherHumans
:List<AnotherHuman> duplicates = new List<AnotherHuman>(); foreach(Human human in humans) { AnotherHuman newAnotherHuman = new AnotherHuman(); newAnotherHuman.LastName = human.LastName; newAnotherHuman.Name= human.Name; newAnotherHuman.Birthday= human.Birthday; duplicates.Add(human) } anotherHumans = anotherHumans.Except(duplicates).ToList();
But how can I compare
PersonalID
from both lists if it presents (it is nullable). Is there any way to get rid from creating new instance of AnotherHuman and list of duplicates and use LINQ only?Thanks in advance!
-
spender over 10 yearsFor every item in anotherHumans, you'd need to iterate the humans collection, so performance of this would degrade significantly as the sizes of the collections increase.
-
spender over 10 yearsThis will only compare items that have a
PersonalID
. I don't think that this is what was asked. -
spender over 10 yearsStill not so good, because in the case that a
PersonalID
is present, there's no requirement to check the LastName, Name and Age, right? -
NinjaNye over 10 yearsI've updated the
PersonalID
fix. With regard to performance, I agree that this will degrade with large datasets however I am not sure this is a concern of the op -
NinjaNye over 10 years
LastName
,Name
, andBirthday
are always checked. The final line will return true if thePersonalId
is null or thePersonalId
matches that of another human -
Gyuzal R over 10 yearsHow do you use lambda expression in Contains()?? It must accept an object,isn't it? Contains(human)?
-
NinjaNye over 10 yearsSorry my fault. should be
.Any
. Updating -
Gyuzal R over 10 yearsAny() returns a bool value, you cannot convert it ToList()
-
NinjaNye over 10 yearsI was missing a bracket at the end (before the
.ToList()
). you probably are to