开发者

Generate a unique value for a combination of two numbers

开发者 https://www.devze.com 2023-01-26 12:23 出处:网络
Consider I\'ve two numbers 1023232 & 44. I want to generate a unique number representing this com开发者_运维百科bination of numbers. How can i generate it?

Consider I've two numbers 1023232 & 44. I want to generate a unique number representing this com开发者_运维百科bination of numbers. How can i generate it?

Requirement

f(x,y) = f(y,x) and f(x,y) is unique for every (x,y) or (y,x)


if those are two ints, you could just do this:

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

if you need to generate a truly unique value for two variables of a given size, you need about double the size of each variable. (ok, a bit less now that f(x,y) == f(y,x))

You could also get your original values back by reversing the same operation.


If you are using ints and don't mind the result being a long, this should work:

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

The fact that the numbers are stored in the high and low dwords of the result get you your uniqueness constraint.

The fact that the higher number is always in the high dword gets you the symmetry you wanted.


Use the fact that length of Int32 as string is <= 10, store the length of the first int's string representation modulo 10 as the last digit of an 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"

result = 1023232202440

To decode this you just need to extract the last digit of the string representation (encoded) and then convert the other digits back to int using two calls to 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));

To handle negatives - since # of digits <= 10, you could add two more data bits in the last digit to store a sign for each of your ints - 1 for positive, 0 for negative. Also - result won't fit in Int64 if both of your ints are very large, you would have to use BigInteger from System.Numerics


You could use the function given here. This is the most space efficient I have seen and also doesn't involve any string approaches. The native function in the link won't work for negative integers though. But you can modify it as shown below to make it work for negative integers.

This will give back negative results too. For more on it and other options 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;
}


Botz3000 gives the "correct" solution. I'd just add: To solve the problem, you must know the maximum possible size of each number, and an acceptable result must be the sum of the sizes of the two numbers. i.e. if each number is guaranteed to fit in 32 bits, as Botz3000 assumes, then the result will require 64 bits. If that is not acceptable -- if, say, you have a requirement that the input will be two 32 bit numbers and the output must fit in 32 bits -- then the problem is not solvable, because there aren't enough possible different answers.

If that's not clear, consider a trivial case: suppose the inputs are each 1 bit, 0 or 1. So there are two possible values for each number, 2x2=4 possible combinations. Therefore your output must be at least 2 bits. As you say that f(x,y)=f(y,x), you reduce the total number of possible answers by a factor somewhat less than 2. Again, in the 1 bit example, there are only 3 distinct possibilities: 0,0; 0,1; and 1,1. 1,0 isn't a distinct possibility because it's the same as 0,1.


First you have to know you cannot make uniq value from two int.MaxValue to one int, and @Botz3000 answer don't make uniq value from F(1,2) and F(2,1) so you can use this method:

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

This will work for anything and you can change result and parameters to short,ushort,int,uint, or result for ulong because its working with bytes.you need just change BitConverter method as you want to convert.

Example for get smaller value (from two small int you will get small long):

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


If you can represent it as a string, this should work:

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

Like so:

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


You can combine the two numbers into a string, and generate a hash based on that string using SHA1.


If X & Y are Int add a seperator. Always unique.

X = 100, Y = 5 => 100.5

X = 1023232, Y = 44 => 1023232.44

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号