是否可以从GUID生成(极可能的)唯一整数?
int i = Guid.NewGuid().GetHashCode();
int j = BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0);
哪一个更好?
答案 0 :(得分:44)
Eric Lippert发表了关于probability of hash collisions的一篇非常有趣(一如既往)的帖子。
你应该阅读所有内容,但他总结了这个非常具有说明性的图表:
与您的具体问题相关,我也会选择GetHashCode
,因为碰撞无论如何都是不可避免的。
答案 1 :(得分:17)
GetHashCode
函数专门用于创建一个分布均匀的整数范围,具有较低的碰撞概率,因此对于这个用例可能是您可以做的最好的。
但是,我确信您已经知道,将128位信息散列到32位信息中会丢弃大量数据,因此如果您拥有足够多的GUID,几乎肯定会发生冲突。 / p>
答案 2 :(得分:16)
这是最简单的方法:
Guid guid = Guid.NewGuid();
Random random = new Random();
int i = random.Next();
你会注意到guid
实际上并没有在这里使用,主要是因为使用它没有意义。微软的GUID算法不再使用计算机的MAC地址 - GUID实际上是使用伪随机生成器(基于时间值)生成的,所以如果你想要一个随机整数,那么使用Random
类更有意义对此。
更新:实际上,使用GUID生成int
可能比仅使用Random
更糟糕(“更差”,因为这将是更有可能生成冲突)。这是因为并非GUID中的所有128位都是随机的。理想情况下,您可能希望从散列函数中排除非变量位,尽管生成随机数会容易得多,正如我之前提到的那样。 :)
答案 3 :(得分:11)
GUID是一个128位整数(它只是十六进制而不是十进制)。使用.NET 4,使用http://msdn.microsoft.com/en-us/library/dd268285%28v=VS.100%29.aspx,如下所示:
// Turn a GUID into a string and strip out the '-' characters.
BigInteger huge = BigInteger.Parse(modifiedGuidString, NumberStyles.AllowHexSpecifier)
如果您没有.NET 4,可以查看IntX或Solver Foundation。
答案 4 :(得分:5)
因为GUID空间大于32位整数的数量,所以如果您有足够的GUID,则可以保证发生冲突。鉴于你理解并准备好处理碰撞,无论多么罕见,GetHashCode()都是为了这个目的而设计的,应该是首选。
答案 5 :(得分:5)
如果您希望突破2 ^ 32障碍,请尝试以下方法:
/// <summary>
/// Generate a BigInteger given a Guid. Returns a number from 0 to 2^128
/// 0 to 340,282,366,920,938,463,463,374,607,431,768,211,456
/// </summary>
public BigInteger GuidToBigInteger(Guid guid)
{
BigInteger l_retval = 0;
byte[] ba = guid.ToByteArray();
int i = ba.Count();
foreach (byte b in ba)
{
l_retval += b * BigInteger.Pow(256, --i);
}
return l_retval;
}
在你遇到碰撞之前,宇宙会衰变到寒冷和黑暗的地方。
答案 6 :(得分:2)
我有一个要求,即控制台应用程序的多个实例需要获取唯一的整数ID。它用于标识实例并在启动时分配。因为.exe是用手启动的,所以我使用开始时间的刻度来确定解决方案。
我的理由是,用户几乎不可能在相同的毫秒内启动两个.exe。这种行为是确定性的:如果你有碰撞,你知道问题是两个实例同时启动。取决于哈希码,GUID或随机数的方法可能会以不可预测的方式失败。
我将日期设置为0001-01-01,添加当前时间并将刻度除以10000(因为我没有设置微秒)以获得足够小的数字以适合整数。
var now = DateTime.Now;
var zeroDate = DateTime.MinValue.AddHours(now.Hour).AddMinutes(now.Minute).AddSeconds(now.Second).AddMilliseconds(now.Millisecond);
int uniqueId = (int)(zeroDate.Ticks / 10000);
编辑:有一些警告。为了不太可能发生碰撞,请确保:
答案 7 :(得分:1)
在静态类中,保留一个静态const整数,然后在每次访问之前为其添加1(使用公共get属性)。这将确保在获得非唯一值之前循环整个int范围。
/// <summary>
/// The command id to use. This is a thread-safe id, that is unique over the lifetime of the process. It changes
/// at each access.
/// </summary>
internal static int NextCommandId
{
get
{
return _nextCommandId++;
}
}
private static int _nextCommandId = 0;
这将在正在运行的进程中生成唯一的整数值。由于您没有明确定义整数的唯一性,因此可能适合。
答案 8 :(得分:1)
也许不是整数而是小的唯一键,无论如何短于guids:
http://www.codeproject.com/Articles/14403/Generating-Unique-Keys-in-Net