为两个订单 ID 的排列创建唯一的哈希码
本文关键字:ID 排列 创建 哈希码 唯一 两个 | 更新日期: 2023-09-27 18:23:56
我有一个集合,它是两个唯一订单的排列,其中 OrderId 是唯一的。因此,它包含Order1 (Id = 1)
和Order2 (Id = 2)
,既12
又21
。现在,在处理路由算法时,检查的条件很少,当组合包含在最终结果中时,必须忽略其反向,并且无需考虑进行处理。现在,由于 Id 是一个整数,我创建了一个以下逻辑:
private static int GetPairKey(int firstOrderId, int secondOrderId)
{
var orderCombinationType = (firstOrderId < secondOrderId)
? new {max = secondOrderId, min = firstOrderId}
: new { max = firstOrderId, min = secondOrderId };
return (orderCombinationType.min.GetHashCode() ^ orderCombinationType.max.GetHashCode());
}
在逻辑中,我创建了一个Dictionary<int,int>
,其中键是使用上面显示的方法创建的GetPairKey
其中我确保在给定的组合中正确排列它们,以便我得到相同的哈希码,可以插入并检查字典中的条目,而它的值是虚拟的,它被忽略了。
但是上面的逻辑似乎有一个缺陷,它不能像预期的那样对所有逻辑处理工作,在这种情况下我做错了什么,我应该尝试一些不同的东西来创建Hashcode
.像下面的代码是更好的选择,请建议
Tuple.Create(minOrderId,maxOrderId).GetHashCode
,以下是相关的代码用法:
foreach (var pair in localSavingPairs)
{
var firstOrder = pair.FirstOrder;
var secondOrder = pair.SecondOrder;
if (processedOrderDictionary.ContainsKey(GetPairKey(firstOrder.Id, secondOrder.Id))) continue;
添加到字典的是以下代码:
processedOrderDictionary.Add(GetPairKey(firstOrder.Id, secondOrder.Id), 0);
这里的值 0 是虚拟的,没有使用
您需要一个可以唯一表示每个可能值的值。
这与哈希代码不同。
您可以使用long
或包含所有适当值的类或结构唯一地表示每个值。由于在一定总大小之后使用 long
将不再起作用,让我们看看另一种方法,它更灵活、更可扩展:
public class KeyPair : IEquatable<KeyPair>
{
public int Min { get; private set; }
public int Max { get; private set; }
public KeyPair(int first, int second)
{
if (first < second)
{
Min = first;
Max = second;
}
else
{
Min = second;
Max = first;
}
}
public bool Equals(KeyPair other)
{
return other != null && other.Min == Min && other.Max == Max;
}
public override bool Equals(object other)
{
return Equals(other as KeyPair);
}
public override int GetHashCode()
{
return unchecked(Max * 31 + Min);
}
}
现在,这里的GetHashCode()
不会是唯一的,但KeyPair
本身将是独一无二的。理想情况下,哈希码彼此非常不同,以便更好地分布这些对象,但比上述要好得多取决于在实践中看到的实际值的信息。
字典将使用它来查找项目,但它也将使用Equals
在哈希代码相同的项目之间进行选择。
(您可以通过拥有一个GetHashCode()
总是只返回 0
的版本来试验这一点。它的性能会很差,因为碰撞会损害性能,并且这总是会碰撞,但它仍然有效(。
首先,42.GetHashCode()
返回 42。其次,1 ^ 2
与2 ^ 1
相同,因此对数字进行排序实际上没有意义。第三,你的"哈希"函数非常弱,会产生很多冲突,这就是你观察缺陷的原因。
我现在能想到的有两种选择:
- 使用稍微"强"的哈希函数
- 将
Dictionary<int, int>
键替换为Dictionary<string, int>
键,键是两个排序的数字,由您指定的任何字符分隔 - 例如56-6472
鉴于 XOR 是可交换的(所以(a ^ b)
总是与(b ^ a)
相同(,在我看来,您的排序是错误的......我只是
(new {firstOrderId, secondOrderId}).GetHashCode()
.Net 将为匿名类型修复一个很好的分布式哈希实现。