如何在 LINQ 中比较两个不同大小的列表

本文关键字:两个 列表 LINQ 比较 | 更新日期: 2023-09-27 17:57:08

假设我和objectAListA

objectA有姓名,年龄,罗尔诺,等级

和其他ListBobjectB.

objectB有姓名,年龄

如何比较两个列表并根据姓名和年龄过滤掉不常见的记录。

如何在 LINQ 中比较两个不同大小的列表

下面是类的示例:

public interface IHaveNameAndAge
{
    string Name { get; set; }
    int Age { get; set; }
}
public class ObjectA : IHaveNameAndAge
{
    public string Name { get; set; }
    public int Age { get; set; }
    int RollNo { get; set; }
    int Rank { get; set; }
}
public class ObjectB : IHaveNameAndAge
{
    public string Name { get; set; }
    public int Age { get; set; }
}
public class MyEqualityComparer : IEqualityComparer<IHaveNameAndAge>
{
    public bool Equals(IHaveNameAndAge x, IHaveNameAndAge y)
    {
        if (ReferenceEquals(x, y))
            return true; 
        return x.Age == y.Age && String.Equals(x.Name, y.Name, StringComparison.Ordinal);
    }
    public int GetHashCode(IHaveNameAndAge obj)
    {
        return obj.Age.GetHashCode() ^ obj.Name.GetHashCode();
    }
}

以下是测试代码:

var listA = new List<ObjectA>();
listA.Add(new ObjectA() { Name = "A", Age = 20 });
listA.Add(new ObjectA() { Name = "B", Age = 25 });
var listB = new List<ObjectB>();
listB.Add(new ObjectB() { Name = "A", Age = 20 });
listB.Add(new ObjectB() { Name = "C", Age = 29 });
var myComparer = new MyEqualityComparer();
var result = listA.Intersect<IHaveNameAndAge>(listB, myComparer);

您可以根据需要修改此示例。

这里有一个小技巧,用于比较没有通用基本类型的不同类型。创建一个IEqualityComparer<object>,例如:

public class DynamicComparer : IEqualityComparer<object>
{
    public bool Equals(dynamic x, dynamic y)
    {
        return x.Name == y.Name && x.Age == y.Age;
    }
    public int GetHashCode(dynamic obj)
    {
        return ((string)obj.Name).GetHashCode() * 31
            + ((int)obj.Age).GetHashCode();
    }
}

然后你可以这样做:

var filtered = ListA.Intersect(ListB, new DynamicComparer())
                    .Cast<objectA>().ToList();

它是如何工作的。由于object是所有类型的通用基类型,因此IEqualityComparer<object>适用于不同类型的基本类型。但是,我们通常无法比较NameAge属性,因为它们未在object中定义。这里的诀窍是,编译器允许您在IEqualityComparer<object>方法签名中放置dynamic代替object,并且这些签名仍然履行协定。因此,我们可以利用动态运行时来比较objectAobjectB类型共有的属性。