Roc*_*oci 3 c# dictionary hashtable iequalitycomparer
我希望实现一个 IEqualityComparer 类,用于存储和比较四舍五入到最接近的 0.01 的浮点键。特别是,我想确保正确实现 GetHashCode 方法。我想让这尽可能高效。我可以只使用浮点值本身作为它自己的哈希值吗?
我可以乘以 100,转换为 int 并使用 int 作为键,但我很好奇是否可以使用 float 键来完成此操作。
注意:我会将字典包装在一个类中,以确保只添加或比较四舍五入到 0.01 的值。
后续问题:如果我使用 Decimal(保证始终四舍五入为 0.01),我可以仅使用 Decimal 与字典中的 Decimal 键的默认比较器吗?
我的第一个想法是尝试这个实现。有什么陷阱吗?
class FloatEqualityComparer : IEqualityComparer<float>
{
public bool Equals(float b1, float b2)
{
int i1 = (int)(b1 * 100);
int i2 = (int)(b2 * 100);
if(i1 == i2)
return true;
else
return false;
}
public float GetHashCode(float x)
{
return x;
}
}
Run Code Online (Sandbox Code Playgroud)
问题在于GetHashCode执行。如果两个值可能被视为相等,则它们必须产生相同的哈希码。产生不同哈希码的值被认为是不相等的。
为什么不
sealed class FloatEqualityComparer : IEqualityComparer<float>
{
public bool Equals(float x, float y) => Math.Round(x, 3) == Math.Round(y, 3);
public int GetHashCode(float f) => Math.Round(f, 3).GetHashCode();
}
Run Code Online (Sandbox Code Playgroud)
这样做的原因是,如果两个哈希码不同,则不会执行相等测试。这是非常高效的,可以显着提高性能,因为Equals只需针对具有相同哈希码的元素对调用该方法。否则,每个值都需要与其他值进行比较,从而导致计算复杂度为 O(N 2 )。
另一种说法是,如果两个元素应该相互比较是否相等,因为它们的哈希码必须发生冲突。
最后,我们将清理我们的实现以删除重复的代码,并遵循 Microsoft 推荐的提供自定义相等比较器的做法。
sealed class FloatEqualityComparer : EqualityComparer<float>
{
public override bool Equals(float x, float y) => GetEquatable(x) == GetEquatable(y);
public override int GetHashCode(float f) => GetEquatable(f).GetHashCode();
private static float GetEquatable(float f) => Math.Round(f, 3);
}
Run Code Online (Sandbox Code Playgroud)
这会删除重复的代码,防止相等和散列逻辑在修改时发生偏离。它还遵循 Microsoft 的建议,即优先选择扩展EqualityComparer<T>而不是直接实施IEqualityComparer<T>。后一个更改是 BCL 公开的相等比较 API 所特有的,绝不是一般准则,记录在此处。请注意,在这种方法下接口仍然是实现的,因为实现是从基类继承的。
| 归档时间: |
|
| 查看次数: |
3259 次 |
| 最近记录: |