Whats the 'modern' way to find common items in two Lists<T> of objects?
Asked Answered
B

1

11

I have two Generic Lists containing different types, for the sake of example, lets call them Products and Employees. I'm trying to find Products that are based at the same location as Employees, i.e. where product.SiteId == emp.SiteId

List<Product> lstProds;
List<Employees> lstEmps;

My (old skool) brain is telling me to use a forEach loop to find the matches but I suspect there is a ('better'/terser/faster?) way to do it using Linq. Can anyone illuminate me? All the examples I've found online deal with Lists of primitives (strings/ints) and are not especially helpful.

Bonze answered 26/7, 2011 at 9:6 Comment(0)
I
19

I would say:

var products = from product in lstProds
               join employee in lstEmps on product.SiteId equals employee.SiteId
               select product;

However, if there are multiple employees with the same site ID, you'll get the products multiple times. You could use Distinct to fix this, or build a set of site IDs:

var siteIds = new HashSet<int>(lstEmps.Select(emp => emp.SiteId));

var products = lstProds.Where(product => siteIds.Contains(product.SiteId));

That's assuming SiteId is an int - if it's an anonymous type or something similar, you may want an extra extension method:

public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source)
{
    return new HashSet<T>(source);
}

Then:

var siteIds = lstEmps.Select(emp => emp.SiteId).ToHashSet();
var products = lstProds.Where(product => siteIds.Contains(product.SiteId));

Alternatively, if you have few employees, this will work but is relatively slow:

var products = lstProds.Where(p => lstEmps.Any(emp => p.SiteId == emp.SiteId));

Add a ToList call to any of these approaches to get a List<Product> instead of an IEnumerable<Product>.

Imco answered 26/7, 2011 at 9:8 Comment(3)
I had to modify the syntax slightly to get it to work - using == to test for equality is, apparently not correct? VS tells me its 'expecting contextual keyword 'equals''. Replacing == with equals seems to do the trick, but at this point I have no idea why? Could you elaborate please ...?Bonze
@5arx: Sorry, yes, fixed. That's just part of query expression syntax - you're not actually providing a single expression (product.SiteId == employee.SiteId) to check on every pair. Instead, you're providing two projections (product.SiteId and employee.SiteId) which are applied to each element of each side once, and then the keys are compared for equality.Imco
Ok. I think I'm slowly beginning to see. Thanks much :-)Bonze

© 2022 - 2024 — McMap. All rights reserved.