我假设有一个简单的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)


当前回答

一旦你写了一个通用的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);
}

其他回答

由于迄今为止所有的解决方案都使用了流畅的语法,这里有一个查询表达式语法的解决方案,如果你感兴趣的话:

var peopleDifference = 
  from person2 in peopleList2
  where !(
      from person1 in peopleList1 
      select person1.ID
    ).Contains(person2.ID)
  select person2;

我认为它与给出的答案有很大的不同,有些人对此很感兴趣,甚至认为它很可能不是list的最佳选择。现在对于索引id的表,这肯定是可行的方法。

有点晚了,但一个很好的解决方案,也是Linq到SQL兼容的是:

List<string> list1 = new List<string>() { "1", "2", "3" };
List<string> list2 = new List<string>() { "2", "4" };

List<string> inList1ButNotList2 = (from o in list1
                                   join p in list2 on o equals p into t
                                   from od in t.DefaultIfEmpty()
                                   where od == null
                                   select o).ToList<string>();

List<string> inList2ButNotList1 = (from o in list2
                                   join p in list1 on o equals p into t
                                   from od in t.DefaultIfEmpty()
                                   where od == null
                                   select o).ToList<string>();

List<string> inBoth = (from o in list1
                       join p in list2 on o equals p into t
                       from od in t.DefaultIfEmpty()
                       where od != null
                       select od).ToList<string>();

向http://www.dotnet-tricks.com/Tutorial/linq/UXPF181012-SQL-Joins-with-C致敬

Klaus的回答很好,但是ReSharper会让你“简化LINQ表达式”:

var result = peopleList2。Where(p => peopleList1.)p2 => p2。= p.ID));

如果你重写了人员的平等性,那么你也可以使用:

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));

此变体不删除重复项。

{
    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 });
    }

    var leftPeeps = peopleList2.Where(x => !peopleList1.Select(y => y.ID).Contains(x.ID))?.ToList() ?? new List<Person>();
}

class Person
{
    public int ID { get; set; }
}

注意!peopleList1。Select(y => y. id). contains (x.ID)选择语句。这允许我们获取我们想要的索引器(ID),并查看它是否包含前一个列表的ID。! 意思是我们不想要这些。这可能会让我们没有条目。因此,我们可以通过检查null和使用null并结来确保我们有一些东西。