使用带有容差的 IEqualityComparer GetHashCode

Posted

技术标签:

【中文标题】使用带有容差的 IEqualityComparer GetHashCode【英文标题】:Using IEqualityComparer GetHashCode with a tolerance 【发布时间】:2017-05-20 10:16:07 【问题描述】:

我正在尝试实现一个IEqualityComparer,它对日期比较有一个容差。我还研究了this question。问题是我无法使用解决方法,因为我在 LINQ .GroupJoin() 中使用了IEqualityComparer。我已经尝试了一些允许容忍的实现。我可以让Equals() 工作,因为我有两个对象,但我不知道如何实现GetHashCode()

我最好的尝试是这样的:

public class ThingWithDateComparer : IEqualityComparer<IThingWithDate>

    private readonly int _daysToAdd;

    public ThingWithDateComparer(int daysToAdd)
    
        _daysToAdd = daysToAdd;
    

    public int GetHashCode(IThingWithDate obj)
    
        unchecked
        
            var hash = 17;
            hash = hash * 23 + obj.BirthDate.AddDays(_daysToAdd).GetHashCode();
            return hash;
        
    

    public bool Equals(IThingWithDate x, IThingWithDate y)
    
        throw new NotImplementedException();
    


public interface IThingWithDate

    DateTime BirthDate  get; set; 

随着.GroupJoin()GetHashCode() 之外构建HashTable,它将应用天数添加到两个/所有对象。这不起作用。

【问题讨论】:

dayToAdd 容差,如 1 月 5 日等于 1 月 6 日,在 1 天的容差内吗?这个相等的定义不是传递的,所以我怀疑在为每个对象返回相同哈希码的简单解决方案之外使用 IEqualityComparer 是否可以正确实现。 算了。将GroupJoin 替换为SelectMany 和简单的Where(性能不是很好,但应该可以)。 @mikez 是的,这就是容差。只是名字不好。如果我不能完成这项工作,我将只实现GroupJoin() 的自定义版本。 @IvanStoev 性能是个问题。我们匹配的当前解决方案使用 where 并且它提供了可怕的性能。通过使用GroupJoin(),我能够将 9 小时的过程缩短到几毫秒。 我知道(并且总是关心 .poerformance)。但慢工作总比不工作好。真正的用例是什么,我们可以考虑别的吗? 【参考方案1】:

从概念上讲,这个问题是不可能的。您正在尝试以不具有您尝试使用它执行的操作所必需的相等形式的方式比较对象。例如,GroupJoin 依赖于假设如果 A 等于 B,B 等于 C,那么 A 等于 C,但在您的情况下,这是不正确的。 A 和 B 可能“足够接近”让您想将它们分组,但 A 和 C 可能不是。

您将根本不需要实现IEqualityComparer,因为您无法履行它所要求的合同。如果您想创建一个集合中的项目到另一个集合中“足够接近”的所有项目的映射,那么您将需要自己编写该算法(有效地这样做可能很困难,但是这样做效率低下应该不那么困难),而不是使用GroupJoin,因为它无法执行该操作。

【讨论】:

这似乎是正确的答案。令人失望的是答案是没有答案。【参考方案2】:

我看不到任何方法可以为您的给定条件生成逻辑哈希码。 哈希码用于确定两个日期是否应该粘在一起。如果它们应该组合在一起,那么它们必须返回相同的哈希码。

如果您的“浮动”为 5 天,这意味着 1/1/2000 必须生成与 1/4/2000 相同的哈希码,并且 1/4/2000 必须生成与 1/8/2000 相同的哈希码(因为它们都在 5 天内)。这意味着 2000 年 1 月 1 日的代码与 2000 年 1 月 8 日的代码相同(因为如果 a=b 和 b=c,a=c)。

2000 年 1 月 1 日和 2000 年 1 月 8 日在 5 天“浮动”之外。

【讨论】:

非常正确。我想我将不得不放弃使用GroupJoin 并实现一个允许Comparer 左侧有种子的版本。

以上是关于使用带有容差的 IEqualityComparer GetHashCode的主要内容,如果未能解决你的问题,请参考以下文章

通用 IEqualityComparer 使用反射和属性来标记我想要比较的内容

List Except 操作,IEqualityComparer 使用

在 IEqualityComparer 中包装委托

如何实现 IEqualityComparer 以返回不同的值?

c#List结合IEqualityComparer求交集

有没有办法从 IComparer 派生 IEqualityComparer?