C#合并两个具有相同值的列表

时间:2017-12-08 08:56:21

标签: c#

这是我的客户类:

public class Clients
{
    public string Email { get; set; }
    public string Name { get; set; }


    public Clients(string e, string n)
    {
        Email = e;
        Name = n;
    }

我想创建一个包含列表A和列表B中相同客户端的新列表。 例如: 名单A - 约翰,乔纳森,詹姆斯...... 名单B - 玛莎,简,乔纳森...... 取消订阅者 - 乔纳森

    public static List<Clients> SameClients(List<Clients> A, List<Clients> B)
    {
        List<Clients> Unsubscribers = new List<Clients>();
        Unsubscribers = A.Intersect(B).ToList();
        return Unsubscribers;
    }

然而由于某些原因,我得到空列表,我不知道错误是什么。

2 个答案:

答案 0 :(得分:4)

问题在于,当您比较对象时,EqualsGethashcode用于比较它们。你可以覆盖这两种方法,并根据你的需要提供你自己的实现......下面已经有一个答案,涵盖了如何覆盖这两种方法

然而,通常我更喜欢保持我的实体/模型(或任何你想要称之为它们)非常简单,并保持比较实现细节远离我的模型。在这种情况下,您可以实施IEqualityComparer<TSource>并使用Intersects的重载来接收IEqualityComparer

以下是IEqualityComprarer仅基于Name属性的示例实现...

public class ClientNameEqualityComparer : IEqualityComparer<Clients>
{
    public bool Equals(Clients c1, Clients c2)
    {
        if (c2 == null && c1 == null)
           return true;
        else if (c1 == null | c2 == null)
           return false;
        else if(c1.Name == c2.Name)
            return true;
        else
            return false;
    }

    public int GetHashCode(Client c)
    {
        return c.Name.GetHashCode();
    }
}

基本上,上面的实现仅关注Name属性,如果Clients的两个实例具有Name属性的相同值,则它们被认为是相等的。

现在你可以做以下了......

A.Intersect(B, new ClientNameEqualityComparer()).ToList();

这将产生你期待的结果......

答案 1 :(得分:1)

默认情况下,

Intersect使用GetHashCodeEquals,但您没有覆盖它,因此Object.Equals仅使用compares references。由于所有客户端实例都使用new进行初始化,因此即使它们具有相同的值,它们也是单独的实例。这就是Intersect“认为”没有共同客户的原因。

所以你有几个选择。

  • 实现自定义IEqualityComparer<Clients>并将其传递给Intersect(或许多其他LINQ方法)。这样做的好处是,您可以针对不同的要求实现不同的比较器,而不需要修改原始类
  • Clients覆盖EqualsGetHashCode和/或
  • Clients实施IEquatable<Clients>

例如(显示最后两个,因为其他答案已显示IEqualityComparer<T>):

public class Clients : IEquatable<Clients>
{
    public string Email { get; set; }
    public string Name { get; set; }


    public Clients(string e, string n)
    {
        Email = e;
        Name = n;
    }

    public override bool Equals(object obj)
    {
        return obj is Clients && this.Equals((Clients)obj);
    }

    public bool Equals(Clients other)
    {
        return Email == other?.Email == true
            && Name == other?.Name == true;
    }

    public override int GetHashCode()
    {
        unchecked 
        {
            int hash = 17;
            hash = hash * 23 + (Email?.GetHashCode() ?? 0);
            hash = hash * 23 + (Name?.GetHashCode() ?? 0);
            return hash;
        }
    }
}

值得一读:

Differences between IEquatable<T>, IEqualityComparer<T>, and overriding .Equals() when using LINQ on a custom object collection?