I want to find all items in one collection that do not match another collection. The collections are not of the same type, though; I want to write a lambda expression to specify equality.
A LINQPad example of what I'm trying to do:
void Main() { var employees = new[] { new Employee { Id = 20, Name = "Bob" }, new Employee { Id = 10, Name = "Bill" }, new Employee { Id = 30, Name = "Frank" } }; var managers = new[] { new Manager { EmployeeId = 20 }, new Manager { EmployeeId = 30 } }; var nonManagers = from employee in employees where !(managers.Any(x => x.EmployeeId == employee.Id)) select employee; nonManagers.Dump(); // Based on cdonner's answer: var nonManagers2 = from employee in employees join manager in managers on employee.Id equals manager.EmployeeId into tempManagers from manager in tempManagers.DefaultIfEmpty() where manager == null select employee; nonManagers2.Dump(); // Based on Richard Hein's answer: var nonManagers3 = employees.Except( from employee in employees join manager in managers on employee.Id equals manager.EmployeeId select employee); nonManagers3.Dump(); } public class Employee { public int Id { get; set; } public string Name { get; set; } } public class Manager { public int EmployeeId { get; set; } }
The above works, and will return Employee Bill (#10). It does not seem elegant, though, and it may be inefficient with larger collections. In SQL I'd probably do a LEFT JOIN and find items where the second ID was NULL. What's the best practice for doing this in LINQ?
EDIT: Updated to prevent solutions that depend on the Id equaling the index.
EDIT: Added cdonner's solution - anybody have anything simpler?
EDIT: Added a variant on Richard Hein's answer, my current favorite. Thanks to everyone for some excellent answers!
The Take operator is used to return a given number of rows from a database table and the Skip operator skips over a specifed number of rows in a database table. I create a data context class that has tables or a stored procedure.
Yes it supports General Arrays, Generic Lists, XML, Databases and even flat files. The beauty of LINQ is uniformity.
In a nutshell, LINQ to Objects provides the developer with the means to conduct queries against an in-memory collection of objects. The techniques used to query against such collections of objects are similar to but simpler than the approaches used to conduct queries against a relational database using SQL statements.
This is almost the same as some other examples but less code:
employees.Except(employees.Join(managers, e => e.Id, m => m.EmployeeId, (e, m) => e));
It's not any simpler than employees.Where(e => !managers.Any(m => m.EmployeeId == e.Id)) or your original syntax, however.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With