我假设有一个简单的LINQ查询来做到这一点,我只是不太确定如何。
给定这段代码:
class Program
{
static void Main(string[] args)
{
List<Person> peopleList1 = new List<Person>();
peopleList1.Add(new Person() { ID = 1 });
peopleList1.Add(new Person() { ID = 2 });
peopleList1.Add(new Person() { ID = 3 });
List<Person> peopleList2 = new List<Person>();
peopleList2.Add(new Person() { ID = 1 });
peopleList2.Add(new Person() { ID = 2 });
peopleList2.Add(new Person() { ID = 3 });
peopleList2.Add(new Person() { ID = 4 });
peopleList2.Add(new Person() { ID = 5 });
}
}
class Person
{
public int ID { get; set; }
}
我想执行一个LINQ查询,给我所有人在peopleList2不在peopleList1。
这个例子应该给我两个人(ID = 4 & ID = 5)
如果你重写了人员的平等性,那么你也可以使用:
peopleList2.Except(peopleList1)
Except应该比Where(…Any)变体快得多,因为它可以将第二个列表放入散列表中。Where(…Any)的运行时为O(peopleList1。Count * peopleList2.Count),而基于HashSet<T> (almost)的变体的运行时为O(peopleList1. Count)。Count + peopleList2.Count)。
Except隐式删除重复项。这应该不会影响你的情况,但对于类似的情况可能会是一个问题。
或者如果你想要快速的代码,但不想重写等式:
var excludedIDs = new HashSet<int>(peopleList1.Select(p => p.ID));
var result = peopleList2.Where(p => !excludedIDs.Contains(p.ID));
此变体不删除重复项。
这可以用下面的LINQ表达式来解决:
var result = peopleList2.Where(p => !peopleList1.Any(p2 => p2.ID == p.ID));
通过LINQ表达的另一种方式,一些开发人员认为更易于阅读:
var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));
警告:正如评论中所指出的,这些方法要求O(n*m)操作。这可能没问题,但可能会带来性能问题,特别是在数据集相当大的情况下。如果这不能满足您的性能要求,您可能需要评估其他选项。但是,由于声明的需求是LINQ中的解决方案,所以这里不讨论这些选项。与往常一样,根据项目的性能需求评估任何方法。
如果你重写了人员的平等性,那么你也可以使用:
peopleList2.Except(peopleList1)
Except应该比Where(…Any)变体快得多,因为它可以将第二个列表放入散列表中。Where(…Any)的运行时为O(peopleList1。Count * peopleList2.Count),而基于HashSet<T> (almost)的变体的运行时为O(peopleList1. Count)。Count + peopleList2.Count)。
Except隐式删除重复项。这应该不会影响你的情况,但对于类似的情况可能会是一个问题。
或者如果你想要快速的代码,但不想重写等式:
var excludedIDs = new HashSet<int>(peopleList1.Select(p => p.ID));
var result = peopleList2.Where(p => !excludedIDs.Contains(p.ID));
此变体不删除重复项。
一旦你写了一个通用的FuncEqualityComparer,你就可以在任何地方使用它。
peopleList2.Except(peopleList1, new FuncEqualityComparer<Person>((p, q) => p.ID == q.ID));
public class FuncEqualityComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> comparer;
private readonly Func<T, int> hash;
public FuncEqualityComparer(Func<T, T, bool> comparer)
{
this.comparer = comparer;
if (typeof(T).GetMethod(nameof(object.GetHashCode)).DeclaringType == typeof(object))
hash = (_) => 0;
else
hash = t => t.GetHashCode();
}
public bool Equals(T x, T y) => comparer(x, y);
public int GetHashCode(T obj) => hash(obj);
}