为两个数字的组合生成唯一值

考虑我有两个数字1023232和44.我想生成一个代表这个数字组合的唯一数字。 我怎样才能产生它?

需求

f(x,y)= f(y,x)和f(x,y)对于每个(x,y)或(y,x)是唯一的

如果这是两个整数,你可以这样做:

ulong F(int x, int y) { ulong id = x > y ? (uint)y | ((ulong)x << 32) : (uint)x | ((ulong)y << 32); return id; } 

如果需要为给定大小的两个变量生成一个真正唯一的值,则需要大约每个变量大小的两倍。 (好吧,现在f(x,y)== f(y,x)有点少)

您也可以通过反转相同的操作来恢复原始值。

如果你使用整数并且不介意结果很长,这应该有效:

Math.Max(x, y) << 32 | Math.Min(x, y)

数字存储在结果的高和低双字中这一事实可以获得您的唯一性限制。

事实上,较高的数字始终在高dword中,这样可以获得您想要的对称性。

使用Int32长度为字符串<= 10的事实,将第一个int的字符串表示模10的长度存储为Int64的最后一位:

 int num1 = 1023232202; int num2 = 44; string encoded = num1.ToString() + num2.ToString() + (num1.ToString().Length % 10).ToString(); Int64 result = Convert.ToInt64(encoded); 

encoded =“1023232202440”

结果= 1023232202440

要对此进行解码,您只需要提取字符串表示的最后一位( encoded ),然后使用对Convert.ToInt32(Substring)两次调用将其他数字转换回int

 encoded = result.ToString(); int firstDigits = Convert.ToInt32(encoded[encoded.Length - 1] - '0'); if (firstDigits == 0) { firstDigits = 10; } num1 = Convert.ToInt32(encoded.Substring(0, firstDigits)); num2 = Convert.ToInt32(encoded.Substring(firstDigits, encoded.Length - firstDigits - 1)); 

要处理否定 – 由于数字<= 10,你可以在最后一位数字中再添加两个数据位来存储每个int的符号 – 1表示正数,0表示负数。 另外 – 如果两个int都非常大, result将不适合Int64 ,你必须使用System.Numerics BigInteger

您可以使用此处给出的function 。 这是我见过的最节省空间的,也不涉及任何字符串方法。 但链接中的本机函数不适用于负整数。 但是你可以修改它,如下所示,使其适用于负整数。

这也会给出负面结果。 有关它和其他选项的更多信息, 请参阅此SO答案。

 public static long GetHashCode_OrderIrrelevant(int a, int b) { return GetHashCode(Math.Min(a, b), Math.Max(a, b)); } public static long GetHashCode(int a, int b) { var A = (ulong)(a >= 0 ? 2 * (long)a : -2 * (long)a - 1); var B = (ulong)(b >= 0 ? 2 * (long)b : -2 * (long)b - 1); var C = (long)((A >= B ? A * A + A + B : A + B * B) / 2); return a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1; } 

Botz3000提供“正确”的解决方案。 我只想补充一点:要解决问题,您必须知道每个数字的最大可能大小,并且可接受的结果必须是两个数字大小的总和。 即如果Botz3000假设每个数字保证适合32位,那么结果将需要64位。 如果这是不可接受的 – 例如,如果您要求输入将是两个32位数字并且输出必须符合32位 – 则问题无法解决,因为没有足够的可能不同的答案。

如果不清楚,请考虑一个简单的情况:假设输入分别为1位,0或1.因此每个数字有两个可能的值,2×2 = 4种可能的组合。 因此,您的输出必须至少为2位。 正如你所说的那样f(x,y)= f(y,x),你可以用一个小于2的因子减少可能答案的总数。再次,在1位的例子中,只有3种不同的可能性:0 ,0; 0,1; 和1,1。 1,0不是一个明显的可能性,因为它与0,1相同。

首先你必须知道你不能将两个int.MaxValue中的uniq值设置为一个int,而@ Botz3000答案不会从F(1,2)和F(2,1)中生成uniq值,所以你可以使用这个方法:

 public static long GetFixedCode(int x, int y) { return BitConverter.ToInt64(BitConverter.GetBytes(x).Concat(BitConverter.GetBytes(y)).ToArray(), 0); } 

这将适用于任何事情,您可以将结果和参数更改为short,ushort,int,uint或ulong的结果,因为它使用bytes.you只需要根据需要更改BitConverter方法。

获取较小值的示例(从两个小的int得到小的长):

  public static ulong GetFixedCode(uint x, uint y) { var array1 = BitConverter.GetBytes(x); var array2 = BitConverter.GetBytes(y); List resultArray = new List(); resultArray.AddRange(array1.ToList().GetRange(0, 2)); resultArray.AddRange(array2.ToList().GetRange(0, 2)); resultArray.AddRange(array1.ToList().GetRange(2, 2)); resultArray.AddRange(array2.ToList().GetRange(2, 2)); return BitConverter.ToUInt64(resultArray.ToArray(), 0); } 

如果你可以将它表示为一个字符串,这应该工作:

 Hash((int1 | int2).ToString()); 

像这样:

 public static string Hash(string plaintext) { var hashAlgorithm = new SHA1CryptoServiceProvider(); var unhashedBuffer = Encoding.Default.GetBytes(plaintext); var hashedBuffer = hashAlgorithm.ComputeHash(unhashedBuffer); return Convert.ToBase64String(hashedBuffer); ) 

您可以将这两个数字组合成一个字符串,并使用SHA1基于该字符串生成一个哈希值。

如果X和Y是Int,请添加一个分隔符。 永远独一无二

X = 100,Y = 5 => 100.5

X = 1023232,Y = 44 => 1023232.44