Reputation: 18630
Ok, so I have two lists of items which are of different types.
var whales = new List<Whale>();
var crabs = new List<Crab>();
So they both have the id property. So save the lists have objects with Ids of:
whales: 1, 3, 4, 5 crabs: 1, 2, 3, 4
Ok so I have a query:
var matchedPairs = from c in crabs
from w in whales
where c.Id = w.Id
select new { crab = c, whale = w };
So that works fine for getting the matches. Where I'm having trouble is I want to get a list of crabs that don't have a matching whale ie. Crab Id = 2. Then I want to get the whales that don't have a matching crab ie Whale Id = 5.
Can anyone tell me how to write these queries?
Upvotes: 4
Views: 8302
Reputation: 4812
Maybe something like this:
var unmatchedCrabs = from c in crabs
where !whales.Any(w => w.Id == c.Id)
select c;
Upvotes: 4
Reputation: 56
You need two Left Join by GroupJoin method like this:
var result1 = whales.GroupJoin(crabs, w => w.ID, c => c.ID, (w,cs) => new {WhaleID = w.ID, Matches = cs});
var result2 = crabs.GroupJoin(whales, c => c.ID, w => w.ID, (c, ws) => new {CrabID = c.ID, Matches = ws});
Then, filter the result by what you want.
Upvotes: 0
Reputation: 117084
Here's the neatest looking LINQ that I can think of to do what you need:
var whalesOnly =
from w in whales
join c in crabs on w.Id equals c.Id into gcs
where !gcs.Any()
select w;
var crabsOnly =
from c in crabs
join w in whales on c.Id equals w.Id into gws
where !gws.Any()
select c;
How do these look for you?
BTW, you can do your join query a little nicer like this:
var whalesAndCrabs =
from whale in whales
join crab in crabs on whale.Id equals crab.Id
select new { crab, whale };
Upvotes: 0
Reputation: 14157
You want an outer join:
var crabsWithoutWhales = from c in crabs
join w1 in whales on c.Id equals w1.Id into ws
from w2 in ws.DefaultIfEmpty()
where w2 == null
select c;
Upvotes: 2
Reputation: 6438
var result = crabs.SelectMany(c => whales, (c, w) => new { c, w })
.Where(@t => whales.All(x => x.Id != t.c.Id) && crabs.All(x => x.Id != t.w.Id))
.Select(@t => new {crab = @t.c, whale = @t.w});
Upvotes: 0
Reputation: 6438
if you want to select only crabs.
var result = crabs.Where(c => whales.All(w => w.Id != c.Id));
Upvotes: 12
Reputation: 4893
You can use Union operation from set operations.
To use it you will have to override default Equality comparer and GetHashCode method. Once you have those then you can do something like this:
var matchedPair = crabs.Union(whales);
In your case, you should have a base class; e.g. Animals with Equality comparer. Another option would be to implement IEqualityComparer<>
Upvotes: 1