Каков «современный» способ найти общие элементы в двух списках‹T› объектов?

У меня есть два общих списка, содержащих разные типы, например, давайте назовем их Products и Employees. Я пытаюсь найти Продукты, которые находятся в том же месте, что и Сотрудники, т. е. где product.SiteId == emp.SiteId

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

Мой (старый школьный) мозг говорит мне использовать цикл forEach для поиска совпадений, но я подозреваю, что есть («лучший»/краткий/быстрый?) способ сделать это с помощью Linq. Кто-нибудь может просветить меня? Все примеры, которые я нашел в Интернете, имеют дело со списками примитивов (строки/целые числа) и не особенно полезны.


person indra    schedule 26.07.2011    source источник


Ответы (1)


Я бы сказал:

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

Однако если у несколько сотрудников с одним и тем же идентификатором сайта, вы получите продукты несколько раз. Вы можете использовать Distinct, чтобы исправить это, или создать набор идентификаторов сайтов:

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

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

Это предполагает, что SiteId является int - если это анонимный тип или что-то подобное, вам может понадобиться дополнительный метод расширения:

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

Затем:

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

В качестве альтернативы, если у вас мало сотрудников, это будет работать, но относительно медленно:

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

Добавьте вызов ToList к любому из этих подходов, чтобы получить List<Product> вместо IEnumerable<Product>.

person Jon Skeet    schedule 26.07.2011
comment
Большое спасибо, мистер Скит. - person indra; 26.07.2011
comment
Мне пришлось немного изменить синтаксис, чтобы заставить его работать - использование == для проверки на равенство, по-видимому, неправильно? VS говорит мне, что «ожидает контекстное ключевое слово« равно »». Замена == на equals, кажется, помогает, но на данный момент я понятия не имею, почему? Не могли бы вы уточнить, пожалуйста...? - person indra; 26.07.2011
comment
@5arx: Извините, да, исправлено. Это всего лишь часть синтаксиса выражения запроса — вы на самом деле не предоставляете одно выражение (product.SiteId == employee.SiteId) для проверки каждой пары. Вместо этого вы предоставляете две проекции (product.SiteId и employee.SiteId), которые применяются к каждому элементу каждой стороны один раз, а затем ключи сравниваются на равенство. - person Jon Skeet; 26.07.2011
comment
Ok. Я думаю, что потихоньку начинаю видеть. Спасибо большое :-) - person indra; 26.07.2011