比较包含大量对象的两个列表(第2部分)

时间:2011-05-16 03:17:09

标签: c# linq performance iequalitycomparer

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

通过实现IEqualityComparer接口,可以看出比较的速度有多么令人印象深刻:example here

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

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属性,它不起作用。也许我做错了什么。我认为不可能用实现此接口的小于等号来比较事物。而且,我不明白这个班级的运作方式;我只知道它在整个列表中迭代的速度令人印象深刻。

4 个答案:

答案 0 :(得分:4)

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

文档:

明确指出:

  

对实施者的说明

     

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

     

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

相反,您需要将IComparable界面或IEqualityComparer与日期比较结合使用。如果你不这样做,事情似乎有效一段时间,但你会后悔。

答案 1 :(得分:3)

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

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

    return rt;

}

答案 2 :(得分:0)

您的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;

}

答案 3 :(得分:0)

我更改了日期部分,因为我还需要时间,因此我使用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;

    }
}

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