【问题标题】:Getting the difference between two Lists based on certain fields根据某些字段获取两个列表之间的差异
【发布时间】:2012-09-26 09:26:39
【问题描述】:

我对 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 };

但是我发现您不能比较多个要比较的字段。

你可以在Left Join 上使用 LINQ 拥有多个字段吗? 还有其他方法(除了 LINQ)来获取两个列表之间的差异吗?

【问题讨论】:

    标签: c# linq join left-join list-comparison


    【解决方案1】:

    这里使用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
    【解决方案2】:

    默认情况下,Except 方法使用EqualityComparer.Default,这就是为什么如果你有不同属性值的对象就不能使用

    但是你可以使用另一个重载方法Except来自定义EqualityComparer&lt;T&gt;,假设它忽略了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... 我认为你的意思是listB 2 号listA
    【解决方案3】:

    怎么样

    一)

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

    b)

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-28
      • 2013-11-14
      • 1970-01-01
      • 1970-01-01
      • 2020-10-30
      相关资源
      最近更新 更多