我有两个列表,一个是联系人,另一个是员工。我想生成不是员工的联系人子集。以下表达式似乎可以告诉我有一些不是员工的联系人,现在我需要一个符合该条件的联系人列表:
if(myContacts.Select(c=>c.contactID).Except(employees.Select(e=>e.contactID)).Any()
{
//get the subset of contacts and do stuff to them....
}
蒂亚!
罗恩
var nonEmployees = contacts.Where(w=> ! employees.Any(e=>e.contactID == w.contactID)).ToList();
或者
var nonEmployees = contacts.Where(w=> ! employees.Select(s=>s.contactID).Contains(w.contactID) ).ToList();
如果您的employees
和contacts
序列是相同类型的对象(或者都继承自相同的类型,例如Contact
),那么您可以创建一个EqualityComparer
实例:
public class ContactComparer : EqualityComparer<Contact>
{
public override bool Equals(Contact x, Contact y)
{
if (ReferenceEquals(x, y)) return true;
return x != null && y != null && x.ContactId == y.ContactId;
}
public override int GetHashCode(Contact obj)
{
if (obj == null) throw new ArgumentNullException("obj");
// assuming string
return (obj.ContactId ?? "").GetHashCode();
}
}
这会让你这样做,因此你可以直接返回结果而不必双重查询:
var contactsNotEmployees = myContacts.Except(employees, new ContactComparer()).ToList();
更新:正如您的评论所示,Contact 和 Employee 是不同的类型,您可以考虑使用 ContactId 属性创建一个接口来创建一个共同的纽带。
或者,我建议将您的 except 结果导出到 a HashSet
,然后使用Contains()
from the HashSet
,这是 O(1) 效率(而不是Contains()
在序列上,这是 O(n) 效率):
// get hash set of contact-only IDs
var except = new HashSet<int>(contacts
.Select(c => c.ContactId)
.Except(emplopyees.Select(e => e.ContactId)));
// get the objects for those IDs
var others = contacts.Where(c => except.Contains(c.ContactId)).ToList();
比较使用序列的结果,对于小列表(15 项) Contains()
,HashSet
Contains()
您的速度大约快 50%,对于较长的列表甚至更快。
无论如何,只是把它扔在那里,因为序列 ( ) 上的 Contains()IEnumerable<T>
相对较慢......
我对这两个解决方案进行了超过 1,000,000 次迭代,并得到:
HashSet With Contains() took: 1429 ms, 0.001429 ms/item.
Sequence With Contains() took: 3386 ms, 0.003386 ms/item.
这不是你要找的吗?
myContacts.Select(c=>c.contactID)
.Except(employees.Select(e=>e.contactID)
.ToList()