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

时间:2010-11-19 15:13:21

标签: c# uniqueidentifier

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

要求

f(x,y)= f(y,x)和f(x,y)对于每个(x,y)或(y,x)

是唯一的

9 个答案:

答案 0 :(得分:12)

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

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))

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

答案 1 :(得分:1)

使用Int32作为字符串的长度为&lt; = 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),然后使用两次调用int将其他数字转换回Convert.ToInt32(Substring)

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));

要处理否定数据 - 由于数字数字&lt; = 10,您可以在最后一位数字中再添加两个数据位,以便为每个int s存储一个符号 - 1表示正数,0表示负数。另外,如果result的{​​{1}}非常大,则Int64将不适合int,您必须使用BigInteger中的System.Numerics

答案 2 :(得分:1)

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

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

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

更高的数字总是在高dword中这一事实可以获得你想要的对称性。

答案 3 :(得分:1)

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

这也会给出负面结果。有关它和其他选项的更多信息see this SO answer.

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;
}

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

首先你必须知道你不能将两个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<byte> resultArray = new List<byte>();
        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);
    }

答案 6 :(得分:-1)

如果您可以将其表示为字符串,则应该可以使用:

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);
)

答案 7 :(得分:-1)

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

答案 8 :(得分:-1)

如果X&amp; Y是Int添加一个分隔符。永远是独一无二的。

X = 100,Y = 5 =&gt; 100.5

X = 1023232,Y = 44 =&gt; 1023232.44