c# - 如何从 List<T> 中删除重复项?

标签 c# list

我正在关注 previous post关于从 List<T> 中删除重复项的 stackoverflow在 C# 中。

如果<T>是一些用户定义的类型,例如:

class Contact
{
    public string firstname;
    public string lastname;
    public string phonenum;
}

建议的 (HashMap) 不会删除重复项。我想,我必须重新定义一些方法来比较两个对象,不是吗?

最佳答案

A HashSet<T> 删除重复项,因为它是一个集合...但前提是您的类型适本地定义了相等性。

我怀疑“重复”是指“一个与另一个对象具有相同字段值的对象”——您需要覆盖 Equals/GetHashCode让它工作,和/或实现 IEquatable<Contact> ... 或者您可以提供 IEqualityComparer<Contact>HashSet<T>构造函数。

而不是使用 HashSet<T>可以调用Distinct LINQ 扩展方法。例如:

list = list.Distinct().ToList();

但同样,您需要以某种方式提供适当的平等定义。

这是一个示例实现。请注意我是如何使它不可变的(可变类型的相等性很奇怪,因为两个对象可能前一分钟相等,下一分钟不相等)和 制作 字段私有(private),具有公共(public)属性。最后,我密封了类 - 不可变类型通常应该密封,这样更容易谈论平等。

using System;
using System.Collections.Generic; 

public sealed class Contact : IEquatable<Contact>
{
    private readonly string firstName;
    public string FirstName { get { return firstName; } }

    private readonly string lastName;
    public string LastName { get { return lastName; } }

    private readonly string phoneNumber;
    public string PhoneNumber { get { return phoneNumber; } }

    public Contact(string firstName, string lastName, string phoneNumber)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.phoneNumber = phoneNumber;
    }

    public override bool Equals(object other)
    {
        return Equals(other as Contact);
    }

    public bool Equals(Contact other)
    {
        if (object.ReferenceEquals(other, null))
        {
            return false;
        }
        if (object.ReferenceEquals(other, this))
        {
            return true;
        }
        return FirstName == other.FirstName &&
               LastName == other.LastName &&
               PhoneNumber == other.PhoneNumber;
    }

    public override int GetHashCode()
    {
        // Note: *not* StringComparer; EqualityComparer<T>
        // copes with null; StringComparer doesn't.
        var comparer = EqualityComparer<string>.Default;

        // Unchecked to allow overflow, which is fine
        unchecked
        {
            int hash = 17;
            hash = hash * 31 + comparer.GetHashCode(FirstName);
            hash = hash * 31 + comparer.GetHashCode(LastName);
            hash = hash * 31 + comparer.GetHashCode(PhoneNumber);
            return hash;
        }
    }
}

编辑:好的,响应对 GetHashCode() 的解释请求实现:

  • 我们想结合这个对象的属性的哈希码
  • 我们不会在任何地方检查是否为空,因此我们应该假设其中一些可能为空。 EqualityComparer<T>.Default总是处理这个,这很好......所以我用它来获取每个字段的哈希码。
  • 将多个哈希码合并为一个的“加法和乘法”方法是 Josh Bloch 推荐的标准方法。还有许多其他通用哈希算法,但这个算法适用于大多数应用程序。
  • 我不知道您是否在默认情况下在已检查的上下文中进行编译,所以我将计算放在未检查的上下文中。我们真的不关心重复的乘法/加法是否会导致溢出,因为我们不是在寻找这样的“量级”......只是一个我们可以重复达到相等的数字对象。

顺便说一下,两种处理无效的方法:

public override int GetHashCode()
{
    // Unchecked to allow overflow, which is fine
    unchecked
    {
        int hash = 17;
        hash = hash * 31 + (FirstName ?? "").GetHashCode();
        hash = hash * 31 + (LastName ?? "").GetHashCode();
        hash = hash * 31 + (PhoneNumber ?? "").GetHashCode();
        return hash;
    }
}

public override int GetHashCode()
{
    // Unchecked to allow overflow, which is fine
    unchecked
    {
        int hash = 17;
        hash = hash * 31 + (FirstName == null ? 0 : FirstName.GetHashCode());
        hash = hash * 31 + (LastName == null ? 0 : LastName.GetHashCode());
        hash = hash * 31 + (PhoneNumber == null ? 0 : PhoneNumber.GetHashCode());
        return hash;
    }
}

关于c# - 如何从 List<T> 中删除重复项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3834461/

相关文章:

php - Wordpress 插件 事件日历 - 列出一年内的所有事件

python - 错误: Can't multiply sequence by non-int of type 'Mul'

c# - 在运行时授予管理员权限

javascript - 基于文本框输入的动态文本框创建

c# - NLog 异步目标数据库连接异常 - 如何获取它们?

html - 列表元素在 2 列中水平对齐

python - 使用列表在 python 中进行测验

python - 如何从列表中获取唯一值(删除重复项)?

c# - 将位置从 3D 相机转换为 2D 相机

c# - 中等信任度的 NHibernate 2.1.2