【问题标题】:How to remove duplicates from collection using IEqualityComparer, LinQ Distinct如何使用 IEqualityComparer、LinQ Distinct 从集合中删除重复项
【发布时间】:2013-06-07 11:59:09
【问题描述】:

我无法从集合中删除重复项,我已经为 Employee 类实现了 IEqualityComparer 仍然没有得到输出

static void Main(string[] args)
    {
        List<Employe> Employeecollection = new List<Employe>();

        Employeecollection.Add(new Employe("abc","def"));
        Employeecollection.Add(new Employe("lmn","def"));
        Employeecollection.Add(new Employe("abc", "def"));

        IEnumerable<Employe> coll = Employeecollection.Distinct(new Employe());

        foreach (Employe item in coll)
        {
            Console.WriteLine(item.fName + "   " + item.lName );
        }

    }

下面是Employee类的实现,这里我实现了IEqualityComparer

class Employe : IEqualityComparer<Employe>
{
    public string fName { get; set; }
    public string lName { get; set; }

    public Employe()
    {

    }

    public Employe(string firstName, string LastName)
    {
        this.fName = firstName;
        this.lName = LastName;
    }

    #region IEqualityComparer<pcf> Members

    public bool Equals(Employe x, Employe y)
    {
        if (x.fName == y.fName && x.lName == y.lName)
        {
            return true;
        }

        return false;
    }

    public int GetHashCode(Employe obj)
    {
        return obj.GetHashCode();
    }

    #endregion
}

【问题讨论】:

    标签: c# linq list


    【解决方案1】:

    忘记 IEqualityComparer,直接使用 Linq:

    EmployeeCollection.GroupBy(x => new{x.fName, x.lName}).Select(g => g.First());
    

    【讨论】:

    • 你能解释一下我理解 GroupBy 但什么是 Select(g => g.First()
    • GroupBy 操作将返回一个 IEnumerable IGrouping 项目(它们也是 IEnumerables)。在您的示例中,外部 IEnumerable 中有两个项目:一个 IGrouping,每个“abc”、“def”有两个条目;另一个 IGrouping,其中包含一个“lmn”、“def”条目。 First() 运算符将从内部 IGrouping IEnumerables 中取出第一项。
    • 对于具有多个属性的逻辑,您必须对所有运行速度比异或比较慢的属性进行分组。
    • @NikolaMitev:使用 XOR 计算哈希值在对范围较小的值(例如枚举)进行哈希处理时可能会导致冲突。虽然冲突不会影响类似哈希表的操作的正确性,但它们会使它们变得更加昂贵。 c# 编译器会自动为不太可能发生冲突的匿名对象编写更好的 GetHashCode 实现。我认为,虽然使用 XOR 可能在计算上很便宜,但更好的实现也很轻,并且除了计算哈希码之外还有其他好处。
    • @NikolaMitev:只有在散列的集合中存在冲突时才会发生属性的实际比较。 GroupBy 仍然以与 Distinct 相同的方式使用哈希。我认为您的上述评论具有误导性。
    【解决方案2】:

    这是一个很好的tutorial

        public int GetHashCode(Employe obj)
        {
            return obj.fname.GetHashCode() ^ obj.lname.GetHashCode();
        }
    

    【讨论】:

    • 你不应该在没有实现相等成员的情况下实现 GetHashCode。 GetHashCode 也应该是一个覆盖。还值得记住的是,“当数据结构中存在冗余时,'xor' 会产生或加剧分布问题。”blogs.msdn.com/b/ericlippert/archive/2011/02/28/…
    【解决方案3】:

    您需要在 Employee 中覆盖 GetHashCode 方法。你没有这样做。下面给出了一个好的散列方法的例子:(由ReSharper生成)

    public override int GetHashCode()
    {
        return ((this.fName != null ? this.fName.GetHashCode() : 0) * 397) ^ (this.lName != null ? this.lName.GetHashCode() : 0);
    }
    

    现在在调用Distinct 之后,foreach 循环打印:

    abc   def
    lmn   def
    

    在您的情况下,您正在调用对象的类GetHashCode,它对内部字段一无所知。

    一个简单的说明,MoreLINQ 包含DistinctBy 扩展方法,它可以让你做:

    IEnumerable<Employe> coll = 
     Employeecollection.DistinctBy(employee => new {employee.fName, employee.lName});
    

    匿名对象对GetHashCodeEquals 方法都有正确的实现。

    【讨论】:

      【解决方案4】:

      哈希码实现不正确:

      public override int GetHashCode()
      {
          return 13 * fName.GetHashCode() + 7 * lName.GetHashCode();
      }
      

      【讨论】:

      • 当对象字段之一为空时,是否可以在GetHashCode 中接收NullReferenceException
      • 绝对不是——我只是想我可以澄清“当等于相同时哈希码应该相同”的事实,而不是专注于空检查。但是,是的,你是对的。
      【解决方案5】:

      而且看起来您的比较是通过引用而不是内容,因此比较功能不起作用。

      将其更改为使用 .Equals() 而不是 == 并且它应该可以工作。 下面的例子:

      #region IEqualityComparer<pcf> Members
      
      public bool Equals(Employe x, Employe y)
      {
          if (x.fName.Equals(y.fName) && x.lName.Equals(y.lName))
          {
              return true;
          }
      
          return false;
      }
      
      public int GetHashCode(Employe obj)
      {
          return obj.GetHashCode();
      }
      
      #endregion
      

      【讨论】:

      • == 操作符对 c# 中的字符串工作得很好。问题出在 GetHashCode() 实现中。
      【解决方案6】:
      public int GetHashCode(Employe obj)
      {
          return obj.GetHashCode();
      }
      

      对于此方法,返回您正在比较是否相等的属性的哈希码,而不是对象本身。比较对象的哈希码将始终为false,因此您的列表将永远不会被过滤重复。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-08
        • 2022-01-12
        • 1970-01-01
        • 1970-01-01
        • 2019-02-17
        • 1970-01-01
        • 1970-01-01
        • 2017-10-25
        相关资源
        最近更新 更多