我有一个代码应该从客户端获取唯一的字符串(例如,“d86c52ec8b7e8a2ea315109627888fe6228d”)并返回超过2200000000且小于5800000000的整数。重要的是,这个生成的int不是随机的,它应该是一对一的独特的字串。不使用DB生成它的最佳方法是什么?
现在看起来像这样:
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
答案 0 :(得分:3)
这就是问题 - 您的数字范围只有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
value而不是解析它是一个大整数。请注意,此策略在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
当然,你必须决定如何处理碰撞。您可能必须保留一桶输入字符串,这些输入字符串映射到相同的值,并决定如何通过映射值查找冲突。
答案 1 :(得分:0)
您可以生成32位CRC,丢弃一位,并将结果添加到2.2M。这给你最大值4.3M 或者你可以使用CRC的所有32位,但是当结果太大时,在输入字符串上追加零并重新计算,重复直到得到范围内的值。