Создать уникальное значение для комбинации двух чисел
считайте меня два номера 1023232 & 44. Я хочу создать уникальное число, представляющее эту комбинацию чисел. Как я могу его генерировать?
требование
f(x,y) = f(y,x) и f (x,y) является уникальным для каждого (x,y) или (y,x)
9 ответов
если это два Инта, вы можете просто сделать это:
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))
вы также можете вернуть исходные значения, изменив ту же операцию.
Если вы используете ints и не возражаете, что результат длинный, это должно работать:
Math.Max(x, y) << 32 | Math.Min(x, y)
тот факт, что числа хранятся в высоких и низких словах результата, дает вам ограничение уникальности.
тот факт, что большее число всегда находится в высоком dword, дает вам симметрию, которую вы хотели.
используйте тот факт, что длина Int32
поскольку строка 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);
закодировано = "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));
для обработки негативов-так как # цифр ints-1 для положительного, 0 для отрицательного. Также - result
не будет соответствовать Int64
если оба ваших int
s очень большие, вам придется использовать BigInteger
С System.Numerics
можно использовать функция, приведенная здесь. Это самое эффективное пространство, которое я видел, а также не включает никаких струнных подходов. Однако собственная функция в ссылке не будет работать для отрицательных целых чисел. Но вы можете изменить его, как показано ниже, чтобы он работал для отрицательных целых чисел.
Это также даст отрицательные результаты. Подробнее об этом и других вариантах см. Это так ответ.
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 дает "правильное" решение. Я бы просто добавил: чтобы решить проблему, вы должны знать максимально возможный размер каждого числа, а приемлемым результатом должна быть сумма размеров двух чисел. т. е. если каждое число гарантированно вписывается в 32 бита, как предполагает Botz3000, то результат потребует 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.
сначала вы должны знать, что вы не можете сделать значение uniq из двух int.MaxValue к одному int, и @Botz3000 ответ не делает значение uniq из F (1,2) и F(2,1), поэтому вы можете использовать этот метод:
public static long GetFixedCode(int x, int y)
{
return BitConverter.ToInt64(BitConverter.GetBytes(x).Concat(BitConverter.GetBytes(y)).ToArray(), 0);
}
это будет работать для чего угодно,и вы можете изменить результат и параметры на short,ushort,int, uint или result для ulong, потому что он работает с байтами.вам нужно просто изменить метод 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);
}
Если вы можете представить его как строку, это должно работать:
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);
)
Если X & Y-Int, добавьте разделитель. Всегда уникальный.
X = 100, Y = 5 = > 100.5
X = 1023232, Y = 44 => 1023232.44