Consider I've two numbers 1023232 & 44. I want to generate a unique number representing this combination 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)
Consider I've two numbers 1023232 & 44. I want to generate a unique number representing this combination 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.
long)x
, like PHP used 64 bit by default or so). I do not know PHP. –
Nucleon (long)x << 32 | (uint)y
. I said its inefficient considering the space (also time) it takes to pair two fairly small numbers. This is fast for small numbers. but as size grows the speed hit will be noticeable. I posted a solution which is much faster. –
Nucleon ulong
is slower than long
which my function returns). Nevertheless this is less space efficient. Just saying. –
Nucleon F(int.MinValue, int.MinValue)
and F(-2, -99)
), and i always got correct results. Did you leave the method body unchanged? –
Humbuggery -2
to (uint)? Either you have try catch, or an unchecked
wrapper (ok kidding), or you will have to turn on Check arithmetic oveflow/underflow
from VS project properties->build->advanced->checkbox check.. –
Nucleon (uint)x
, the C# compiler by default doesn't use overflow checking. Constant expressions such as (uint)-2
though, are checked at compile time. That's why it works using the method. –
Humbuggery encoded = (uint)x | ((ulong)y << 32)
to encode and to decode x = encoded >> 32
and y = encoded & xFFFFFFFF
.Am I right? –
Selenodont f(x,y) = f(y,x)
. And if the numbers would not be ordered, you would get a different value for e.g. f(3,5)
and f(5,3)
. –
Humbuggery f(3,5) != f(5,3)
then I guess I do not need the check or? –
Selenodont 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 int
s - 1 for positive, 0 for negative. Also - result
won't fit in Int64
if both of your int
s are very large, you would have to use BigInteger
from System.Numerics
int
s - 1 for positive, 0 for negative. Also - result
won't fit in Int64
if both of your int
s are very large, you would have to use BigInteger
from System.Numerics
. –
Gouda 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.
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);
)
byte[]
or the encoded string.. –
Nucleon 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
100,5
and 100,50
. Also take into consideration the mess if your numbers were large, the resultant might suffer from precision errors.. –
Nucleon © 2022 - 2024 — McMap. All rights reserved.