Генерация целого числа в диапазоне от уникальной строки в ruby - PullRequest
0 голосов
/ 28 февраля 2012

У меня есть код, который должен получить уникальную строку (например, "d86c52ec8b7e8a2ea315109627888fe6228d") от клиента и вернуть целое число больше 2200000000 и меньше 5800000000. Важно, чтобы этот сгенерированный int не был случайным, он должен быть один для одного уникальная строка. Каков наилучший способ его создания без использования БД?

Теперь это выглядит так:

did = "d86c52ec8b7e8a2ea315109627888fe6228d"
min_cid = 2200000000
max_cid = 5800000000
cid = did.hash.abs.to_s.split.last(10).to_s.to_i
if cid < min_cid
  cid += min_cid
else
  while cid > max_cid
    cid -= 1000000000
  end
end

Ответы [ 2 ]

3 голосов
/ 28 февраля 2012

Вот в чем проблема - ваш диапазон чисел имеет только 3,6x10 ^ 9 возможных значений, где в качестве образца уникальная строка (которая выглядит как шестнадцатеричное целое с 36 цифрами) имеет 16 ^ 32 возможных значений (т.е. много Больше).Таким образом, при отображении вашей строки в ваш целочисленный диапазон будут возникать коллизии .

Сама функция отображения может быть довольно простой, я бы сделал что-то подобное, как показано ниже (также рассмотрим использование только частивходной строки для целочисленного преобразования, например, первые семь цифр, если производительность становится критической):

def my_hash(str, min, max)
  range = (max - min).abs
  (str.to_i(16) % range) + min
end

my_hash(did, min_cid, max_cid) # => 2461595789

[Редактировать] Если вы используете Ruby 1.8 и ваш настроенный диапазон может бытьпредставленный как Fixnum, просто используйте hash значение объекта входной строки вместо анализа его как большого целого числа.Обратите внимание, что эта стратегия может быть небезопасной в Ruby 1.9 (согласно комментарию @DataWraith), поскольку значения хеш-объекта могут быть рандомизированы между вызовами интерпретатора, поэтому вы не получите тот же номер хеш-кода для той же строки ввода при перезапуске приложения:

def hash_range(obj, min, max)
  (obj.hash % (max-min).abs) + [min, max].min
end

hash_range(did, min_cid, max_cid) # => 3886226395

И, конечно, вам придется решить, что делать с коллизиями.Скорее всего, вам придется сохранить набор входных строк, которые соответствуют одному и тому же значению, и решить, как разрешить конфликты, если вы ищите по отображенному значению.

0 голосов
/ 28 февраля 2012

Вы можете сгенерировать 32-битный CRC , удалить один бит и добавить результат в 2,2M.Это дает вам максимальное значение 4,3M.
В качестве альтернативы вы можете использовать все 32 бита CRC, но если результат слишком велик, добавьте ноль к входной строке и пересчитайте, повторяя, пока не получите значение в диапазоне.

...