Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using LINQ to Objects to find items in one collection that do not match another

Tags:

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!

like image 854
TrueWill Avatar asked Oct 30 '09 02:10

TrueWill


People also ask

How do you use take and skip in LINQ?

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.

Can LINQ query work with Array?

Yes it supports General Arrays, Generic Lists, XML, Databases and even flat files. The beauty of LINQ is uniformity.

What are the uses of LINQ to objects?

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.


1 Answers

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.

like image 176
Richard Anthony Freeman-Hein Avatar answered Sep 29 '22 19:09

Richard Anthony Freeman-Hein