基于特定字段获取两个列表之间的差异

4
我对LINQ还比较陌生,但是我可能已经把自己限制住了。我有两个列表(左边和右边),需要做到以下几点:
a) 基于某些字段获取匹配项
b) 获取左侧没有匹配项的项目
c) 获取右侧没有匹配项的项目
如果某些字段相等,则视为匹配。其他字段可能包含值,但不能影响匹配比较。
为了获得项目a,我在两个列表上执行了JOIN操作:
var q = from a in r1
        from b in r2
        where a.Prop1 == b.Prop1 && a.Prop3 == b.Prop3
        select new { a.Prop1, a.Prop2, b.Prop3 };

我不确定接下来该怎么做。我认为不能使用.Except(),因为两个列表的其他属性可能不同,这可能会导致比较失败。

我还尝试使用Left Join来获取没有匹配项的项目:

 var q =
     from c in r1
     join p in r2 on c.Prop1 equals p.Prop1
     into cp
     from p in cp.DefaultIfEmpty()
     select new { Prop1 = c.Prop1, Prop2 = p == null ? "N/A" : p.Prop2 };

然而我发现你不能比较多于一个字段。

在LINQ中,可以在左连接中有多个字段吗? 除了LINQ之外,还有其他方法可以获取两个列表之间的差异吗?

3个回答

4

以下代码使用 IntersectExcept(类似于Cuong Le的解决方案):

public class MyComparer : IEqualityComparer<YourClass>
{
    #region IEqualityComparer<YourClass> Members

    public bool Equals(YourClass x, YourClass y)
    {
        return
            x.Prop1.Equals(y.Prop1) && x.Prop3.Equals(y.Prop3);
    }

    public int GetHashCode(YourClass obj)
    {
        int hCode = obj.Prop1.GetHashCode() ^ obj.Prop3.GetHashCode();
        return hCode.GetHashCode();
    }

    #endregion
}

// matched elements from both lists
var r1 = l1.Intersect<YourClass>(l2, new MyComparer());
// elements from l1 not in l2
var r2 = l1.Except<YourClass>(l2, new MyComparer());
// elements from l2 not in l1
var r3 = l2.Except<YourClass>(l1, new MyComparer());

谢谢。我使用了您和Cuong Le的混合解决方案。我不知道有一个“Intersect”,所以它会为我节省“InnerJoin”。 - Devmonster

2
默认情况下,Except 方法使用 EqualityComparer.Default,这就是为什么您不能使用它来比较具有不同属性值的对象。
但是,您可以使用另一个重载方法Except来自定义 EqualityComparer<T>,假设它忽略 Pro3
public class CustomComparer : EqualityComparer<A>
{
    public override int GetHashCode(A a)
    {
        int hCode = a.Pro1.GetHashCode() ^ a.Pro2.GetHashCode();
        return hCode.GetHashCode();
    }

    public override bool Equals(A a1, A a2)
    {
        return a1.Pro1.Equals(a2.Pro1) && a1.Pro2.Equals(a2.Pro2)
    }
}

然后您可以使用Except
listA.Except(listB, new CustomComparer());

谢谢,虽然在你的代码 listA.Except(listA... 中我认为你在第二个 listA 上想表达的是 listB - Devmonster

0
怎么样?

b)

r1.Where(x=>r2.Any(y=>x.Prop1==y.Prop1&&x.Prop3==y.Prop3))
    .Select(x=>new { x.Prop1,x.Prop2,x.Prop3});

乙)

r1.Where(x=>!r2.Any(y=>x.Prop1==y.Prop1&&x.Prop3==y.Prop3))
    .Select(x=>new { x.Prop1,x.Prop2,x.Prop3});

c)

r2.Where(x=>!r1.Any(y=>x.Prop1==y.Prop1&&x.Prop3==y.Prop3))
    .Select(x=>new { x.Prop1,x.Prop2,x.Prop3});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接