C#比较两个相同对象类型的列表

use*_*219 3 c# linq list

我正在尝试使用该类型的多个属性比较两个相同类型的列表。

例如,

我有一个名为Details的类

public class Details
{
    public   int id;
    public string symbol;
    public string code;
}
Run Code Online (Sandbox Code Playgroud)

我有以下两个列表:

List<Details> list1 = new List<Details>();  
List<Details> list2 = new List<Details>();

list1.Add(new Details() { id=1,symbol="ANSI",code="NITE"});
list1.Add(new Details() { id = 1, symbol = "ANSI", code = "CALGO" });
list1.Add(new Details() { id = 1, symbol = "ANSI", code = "CANT" });
list1.Add(new Details() { id=2,symbol="ANSI",code="NITE"});
list1.Add(new Details() { id = 2, symbol = "ANSI", code = "CALGO" });
list1.Add(new Details() { id = 2, symbol = "ANSI", code = "CANT" });

list2.Add(new Details() { id = 1, symbol = "ANSI", code = "NITE" });
list2.Add(new Details() { id = 1, symbol = "ANSI", code = "CALGO" });
list2.Add(new Details() { id = 2, symbol = "ANSI", code = "NITE" });
Run Code Online (Sandbox Code Playgroud)

我只想要来自List1的具有相同ID,符号但不同代码的数据。

因此,在上述情况下结果将如下所示。

list1.Add(new Details() { id = 1, symbol = "ANSI", code = "CANT" });
list1.Add(new Details() { id = 2, symbol = "ANSI", code = "CALGO" });
list1.Add(new Details() { id = 2, symbol = "ANSI", code = "CANT" });
Run Code Online (Sandbox Code Playgroud)

如果可以通过Linq而不是使用foreach来实现,那就太好了。

我在下面尝试过,但这是不正确的。

var temp =list1.Where(x=>list2.Any(z=>x.id==z.id && string.Equals(x.symbol,z.symbol) && !string.Equals(x.code,z.code)));
Run Code Online (Sandbox Code Playgroud)

L.B*_*L.B 6

1)我首先会覆盖Equals(并且GetHashCode

public class Details
{
    public int id;
    public string symbol;
    public string code;

    public override int GetHashCode()
    {
        return (id + symbol + code).GetHashCode();
    }

    public override bool Equals(object obj)
    {
        var other = obj as Details;
        if (other == null) return false;

        return id == other.id && symbol == other.symbol && code == other.code;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用 Linq 作为

var result = list1.Except(list2).ToList();
Run Code Online (Sandbox Code Playgroud)

它返回您期望的结果...


2)Details在不改变对象的情况下,通过实现自定义也可以获得相同的结果IEqualityComparer

public class DetailsComparer : IEqualityComparer<Details>
{
    public bool Equals(Details x, Details y)
    {
        return x.id == y.id && x.symbol == y.symbol && x.code == y.code;
    }

    public int GetHashCode(Details obj)
    {
        return (obj.id + obj.symbol + obj.code).GetHashCode();
    }
}
Run Code Online (Sandbox Code Playgroud)

那么你的 linq 就是

var result = list1.Except(list2, new DetailsComparer()).ToList();
Run Code Online (Sandbox Code Playgroud)

这些方法比利用 和 的 O(n*n) 算法Any更好All


das*_*ght 5

看起来您需要满足两个条件而不是一个条件的行才能生成输出:

  • 需要有匹配的idsymbol,和
  • 必须没有匹配idsymbolcode

这是直接使用LINQ的方法:

var tmp = list1.Where(x=>
    list2.Any(z=>x.id==z.id && x.symbol==z.symbol)
&& !list2.Any(z => x.id==z.id && x.symbol==z.symbol && x.code==z.code));
Run Code Online (Sandbox Code Playgroud)

演示

基于应用戴摩根定律的另一种选择:

var tmp = list1.Where(x=>
    list2.Any(z=>x.id==z.id && x.symbol==z.symbol)
 && list2.All(z => x.id!=z.id || x.symbol!=z.symbol || x.code!=z.code));
Run Code Online (Sandbox Code Playgroud)

演示