【发布时间】:2020-10-10 00:19:42
【问题描述】:
我在获取具有此属性的唯一 int32 标识符时遇到问题:
- 对于当前程序实例中的相同对象,它必须始终相同
- 对于不同的对象,程序的当前实例必须始终不同,因此根本不会发生冲突。
我需要该唯一标识符来比较复杂对象并使用 Dictionary 或 HashSet 等类。
我非常希望避免使用任何类型的哈希表或任何类型的预计算,而是使用一种可以即时执行此操作的算法,以便排除外部依赖并使单元测试更容易
对象的伪代码:
class ComplexObject
{
public readonly FirstEnum First; // ~50 different values
public readonly IFirstModificator FirstModificator; // 4 implementations x 15 values (~60 values total)
public readonly InternalObject[] Internal; //1-10 values in array
}
class InternalObject
{
public readonly SecondEnum Second; // ~30 different values
public readonly SecondModificator SecondModificator; // ~15 different values
}
如果它很重要,我的域模型包含大约 100 000 个 ComplexObject 类型的唯一对象
我已经试过了:
- 将对象序列化为 json 并获取该字符串的哈希(通过使用 string.GetHashCode() 方法)。即使在程序的当前实例中,它也会产生冲突。
- 这样的代码也会产生很多冲突:
unchecked
{
int hash = 17;
hash = hash * 31 + firstField.GetHashCode();
hash = hash * 31 + secondField.GetHashCode();
return hash;
}
unchecked
{
int hash = (int) 17;
hash = (hash * 31) ^ field1.GetHashCode();
hash = (hash * 31) ^ field2.GetHashCode();
return hash;
}
更新:
IFirstModificator 有不同的实现,但总的来说它看起来像这样:
class FirstModificator : IFirstModificator
{
public int Value {get;set;} //~15 values
}
实现IFirstModificator的其他参数影响\仅适用于(不确定我的英语是否清楚)数据处理。
class SecondModificator
{
public int Value {get;set;} //~15 values
}
创建类实例所需的外部接口和数据与实现 IFirstModificator 类似,但它们实际上是不同的类。
【问题讨论】:
-
Int32只有 32 位可供使用,而 simply not enough 可以保证这么多对象的无冲突散列(假设您不能使用值分布的任何特殊属性)。但是请注意,为了正确使用Dictionary等类,不需要无冲突散列;碰撞只是意味着性能会有所降低,因为多个对象将占用同一个桶。在列表中搜索 2 或 3 个碰撞的对象并不比仅获取一个慢多少。 -
如果您对不同值的数量的评论是准确的,那么您实际上似乎没有超过 2^31 个唯一的 possible 对象,这意味着您绝对可以产生唯一散列唯一对象的散列。这实际上涉及为每个组合分配一个唯一编号,因此请根据您的分布对其进行调整(即通过将所有
SecondModificator值映射到 0-15 和Second到 0-30 来散列InternalObject,然后执行SecondModificator * 16 + Second)。当然,这可能比普通哈希要困难得多。 -
请注意,如果您的相等比较非常慢并且是碰撞的瓶颈(可能是非常大的对象的情况),您可以通过计算第二个更大的哈希来加快速度(即使是
Int64就足够了),将其与您的对象(或单独的ConditionalWeakTable)一起存储,并在进行完全相等比较之前检查它是否匹配。但是,您的对象似乎不足以保证这一点,最多占用几个字节。在这成为真正的问题之前,碰撞必须变得非常糟糕。 -
您能否提供一些有关
IFirstModificator和SecondModificator及其实现的详细信息?还有什么构成对象的身份?是否可以有重复的InternalObject对象或重复的ComplexObject对象,必须被视为不同的对象? -
@jeroen-mostert 感谢您的建议。在这种情况下,由于多种原因,不同的(对于域模型参数的重要性不相等)对象不会被放入同一个桶中,但有时会发生冲突,这一点至关重要。