【问题标题】:Compare two lists that contain a lot of objects (2th part)比较两个包含大量对象的列表(第 2 部分)
【发布时间】:2011-05-16 12:50:13
【问题描述】:

参考我之前提出的问题: Compare two lists that contain a lot of objects

令人印象深刻的是,通过实现 IEqualityComparer 接口进行比较的速度有多快:example here

正如我在另一个问题中提到的,这种比较有助于我在目标文件夹上备份源文件夹。知道我想同步到文件夹,因此我需要比较文件的日期。每当我做类似的事情时:

public class MyFileComparer2 : IEqualityComparer<MyFile>
{

    public bool Equals(MyFile s, MyFile d)
    {
        return
            s.compareName.Equals(d.compareName) &&
            s.size == d.size &&
            s.deepness == d.deepness &&
            s.dateModified.Date <= d.dateModified.Date;  // This line does not work. 
            // I also tried comparing the strings by converting it to a string and it does
            // not work. It does not give me an error but it does not seem to include the files
            // where s.dateModified.Date < d.dateModified.Date

    }

    public int GetHashCode(MyFile a)
    {
        int rt = (a.compareName.GetHashCode() * 251 + a.size.GetHashCode() * 251 + a.deepness.GetHashCode() + a.dateModified.Date.GetHashCode());

        return rt;

    }
}

如果我可以使用大于或等于符号做类似的事情,那就太好了。我也尝试使用 tick 属性,但它不起作用。也许我做错了什么。我相信不可能将事物与实现此接口的小于等号进行比较。此外,我不明白这个类是如何工作的;我只知道它遍历整个列表的速度令人印象深刻。

【问题讨论】:

    标签: c# linq performance iequalitycomparer


    【解决方案1】:

    您的整个方法存在根本缺陷,因为您的 IEqualityComparer.Equals 方法不是对称的。这意味着 Equals(file1, file2) 不等于 Equals(file2, file1),因为您使用小于运算符的方式。

    文档:

    明确指出:

    实施者须知

    Equals 方法具有自反性、对称性和传递性。也就是说,如果用于将对象与自身进行比较,则返回true;如果对 y 和 x 为真,则对两个对象 x 和 y 为真;如果对 x 和 y 为真,对 y 和 z 也为真,则对两个对象 x 和 z 为真。

    需要实现来确保如果 Equals 方法为两个对象 x 和 y 返回 true,则 GetHashCode 方法为 x 返回的值必须等于为 y 返回的值。

    您需要将IComparable 接口或IEqualityComparer 与日期比较结合使用。如果你不这样做,事情可能会暂时奏效,但你以后会后悔的。

    【讨论】:

      【解决方案2】:

      由于 DateTime 对象在一个 DateTime 小于另一个的情况下是不同的,因此您将获得对象 sd 的不同哈希码,并且 Equals 方法是不叫。为了使日期比较起作用,您应该从 GetHashCode 方法中删除日期部分:

      public int GetHashCode(MyFile a)
      {
          int rt = ((a.compareName.GetHashCode() * 251 + a.size.GetHashCode())
                                * 251 + a.deepness.GetHashCode()) *251;
      
          return rt;
      
      }
      

      【讨论】:

      • 因为Equals 不是自反的,所以即使使用固定的GetHashCode,这也永远无法工作。
      【解决方案3】:

      您的 GetHashCode 有问题:

      public int GetHashCode(MyFile a)
      {
          int rt = (((a.compareName.GetHashCode() * 251) 
                 + a.size.GetHashCode() * 251)
                 + a.deepness.GetHashCode() *251) 
                 + a.dateModified.Date.GetHashCode();
      
          return rt;
      
      }
      

      【讨论】:

      • 有什么问题?拼出来。并且当您使用它时请注意,如果它不属于平等定义的一部分,那么散列日期可能不是一个好主意。
      【解决方案4】:

      我更改了日期部分,因为我还需要时间,因此我使用 ticks 属性。我摆脱了 dateModified 散列代码,它工作得很好。这是我修改程序的方式。我无法比较日期,因此我使用了 Ticks 属性。

      public class MyFileComparer2 : IEqualityComparer<MyFile>
      {
      
          public bool Equals(MyFile s, MyFile d)
          {
              return
                  s.compareName.Equals(d.compareName) &&
                  s.size == d.size &&
                  s.deepness == d.deepness &&
                  //s.dateModified.Date <= d.dateModified.Date &&
                  s.dateModified.Ticks >= d.dateModified.Ticks
                  ;  
      
          }
      
          public int GetHashCode(MyFile a)
          {
              int rt = (((a.compareName.GetHashCode() * 251)
                      + a.size.GetHashCode() * 251)
                      + a.deepness.GetHashCode() * 251)
                      //+ a.dateModified.Ticks.GetHashCode();                       
                      ;
      
              return rt;
      
          }
      }
      

      我仍然不知道这个哈希码函数是如何工作的。好消息是它工作得很好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多