У меня есть два номера 1023232 и 44. Я хочу сгенерировать уникальный номер, представляющий эту комбинацию чисел. Как я могу его создать?
Требование
f (x, y) = f (y, x) и f (x, y) единственно для каждого (x, y) или (y, x)
У меня есть два номера 1023232 и 44. Я хочу сгенерировать уникальный номер, представляющий эту комбинацию чисел. Как я могу его создать?
Требование
f (x, y) = f (y, x) и f (x, y) единственно для каждого (x, y) или (y, x)
Если это два int, вы можете просто сделать это:
ulong F(int x, int y) {
ulong id = x > y ? (uint)y | ((ulong)x << 32) :
(uint)x | ((ulong)y << 32);
return id;
}
если вам нужно создать поистине уникальное значение для двух переменных заданного размера, вам нужно примерно удвоить размер каждой переменной. (ok, немного меньше теперь, когда f (x, y) == f (y, x))
Вы также можете вернуть свои исходные значения, изменив одну и ту же операцию.
Используйте тот факт, что длина 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"
result = 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
- 1 для положительных, 0 для отрицательных. Кроме того, result
не будет вписываться в Int64
, если оба ваших int
очень велики, вам нужно будет использовать BigInteger
из System.Numerics
Если вы используете ints и не возражаете, чтобы результат был длинным, это должно работать:
Math.Max(x, y) << 32 | Math.Min(x, y)
Тот факт, что числа хранятся в высоком и низком словах результата, дает вам ограничение на уникальность.
Тот факт, что большее число всегда находится в высоком dword, получает вам симметрию, которую вы хотели.
Вы можете использовать функцию указанную здесь. Это наиболее эффективное пространство, которое я видел, а также не требует каких-либо строковых подходов. Однако нативная функция в ссылке не работает для отрицательных целых чисел. Но вы можете изменить его, как показано ниже, чтобы заставить его работать с отрицательными целыми числами.
Это также даст отрицательные результаты. Подробнее об этом и других опциях см. Этот ответ 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 дает "правильное" решение. Я бы просто добавил: Чтобы решить проблему, вы должны знать максимально возможный размер каждого числа, а приемлемый результат должен быть суммой размеров двух чисел. то есть, если каждый номер гарантированно будет соответствовать 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.
Если вы можете представить его как строку, это должно работать:
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