老生常谈,还是那三句话:
学历代表你的过去,能力代表你的现在,学习代表你的将来
十年河东,十年河西,莫欺少年穷
学无止境,精益求精
问题描述:很多时候我们可能需要在极短的时间内生成大量的随机数,但是你可能会发现生成了很多重复的随机数。并不是你所希望生成大量不同的数,或者说相同的数极少。
分析原因:Random是主要产生伪随机数的类,它主要包括两个构造函数(无参构造函数和带一个Int32类型参数的构造函数),无参构造函数主要采用系统时间作为随机种子,带参数的构造函数需要自己去指定随机种子。而在很短的时间内生成大量随机数的时候,由于时间相当短暂,很大的可能性一部分随机数生成时,取到作为随机种子的系统时间相同,因此产生出来的随机数就相同了。
解决方案:既然知道原因何在了,解决方案就可以出来了。要生成不同的随机数,我们只需要保证随机种子尽可能不重复(不能完全保证不重复)即可。Random类有两个构造函数,我们就可以考虑用两种方法去解决这个问题。(有更好、更多的解决办法的朋友,告诉我一声了,呵呵~~)
- 利用无参构造函数,既然它是采用系统时间作为随机种子,而取到的系统时间相同,才造成生成了重复的随机数,因此我们可以在生成一个随机数后延时一段时间,让它下次不取到相同的系统时间,这样随机种子也就不相同了。延时可以考虑使用Thread.Sleep(100),这里是延时0.1秒。
- 利用带参构造函数,我们想办法去生成尽可能不重复的随机种子。注意到MSDN中介绍Random.NextBytes()方法时,有这样一句话“要生成适合于创建随机密码的加密安全随机数,请使用如 RNGCryptoServiceProvider.GetBytes 这样的方法。”,它包含的意义是微软已经有现成的东西生成随机的密码,那我们就可以拿来用用了。我们就用它来生成我们的随机种子。
可以写一个生成随机种子的方法,代码如下:
在此,贴下用法:
public int GetRandSeed() { byte[] bytes = new byte[8]; System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider(); rng.GetBytes(bytes); return BitConverter.ToInt32(bytes, 0); }
然后再贴出一个具体应用。
生成固定前缀的身份证号(北京市市辖区身份证开头 110100):
#region 生成身份证号 /// <summary> /// 身份证后四位 /// </summary> /// <param name="codeLength"></param> /// <returns></returns> /// private string GetCode(int codeLength) { Random rand = new Random(); string so = "1,2,3,4,5,6,7,8,9,0"; string[] strArr = so.Split(','); string code = ""; for (int i = 0; i < codeLength; i++) { code += strArr[rand.Next(0, strArr.Length)]; } return code; } private string GetCodeForIdNo() { byte[] bytes = new byte[8]; System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider(); rng.GetBytes(bytes); int j = Math.Abs(BitConverter.ToInt32(bytes, 0)); if (j.ToString().Length == 1) { return GetCode(3) + j.ToString(); } else if (j.ToString().Length == 2) { return GetCode(2) + j.ToString(); } else if (j.ToString().Length == 3) { return GetCode(1) + j.ToString(); } else if (j.ToString().Length == 4) { return j.ToString(); } else { return j.ToString().Substring(0,4); } } public List<IdCard> CreateIdCard() { string CardFrist = "110100";//北京市市区 List<IdCard> CMlist = new List<IdCard>(); int Year = 1955; List<int> YearList = new List<int>();//年份范围 List<int> monthList = new List<int>();//月份范围 List<int> dayList = new List<int>();//天范围 for (int i = -35; i < 36; i++) { YearList.Add(Year + i); } for (int i = 1; i < 13; i++) { monthList.Add(i); } //不考虑瑞年非闰年及月份的天数 最大28天 for (int i =1; i < 29; i++) { dayList.Add(i); } //dd XiCard(YearList); XiCard(monthList); XiCard(dayList); for (int i = 0; i < 100; i++) { IdCard CM = new IdCard(); int Y_Len=YearList.Count; int M_Len=monthList.Count; int D_Len=dayList.Count; int Nyear = YearList[i % Y_Len]; int Nmonth = monthList[i % M_Len]; int Nday = dayList[i % D_Len]; if (Nmonth < 10&&Nday<10) { CM.BrithDay = Convert.ToDateTime(Nyear.ToString() + "-0" + Nmonth.ToString() + "-0" + Nday.ToString()); CM.IdNo = CardFrist + CM.BrithDay.ToString("yyyyMMdd") + GetCodeForIdNo(); CMlist.Add(CM); } if (Nmonth < 10 && Nday > 10) { CM.BrithDay = Convert.ToDateTime(Nyear.ToString() + "-0" + Nmonth.ToString() + "-" + Nday.ToString()); CM.IdNo = CardFrist + CM.BrithDay.ToString("yyyyMMdd") + GetCodeForIdNo(); CMlist.Add(CM); } if (Nmonth > 10 && Nday > 10) { CM.BrithDay = Convert.ToDateTime(Nyear.ToString() + "-" + Nmonth.ToString() + "-" + Nday.ToString()); CM.IdNo = CardFrist + CM.BrithDay.ToString("yyyyMMdd") + GetCodeForIdNo(); CMlist.Add(CM); } if (Nmonth > 10 && Nday < 10) { CM.BrithDay = Convert.ToDateTime(Nyear.ToString() + "-" + Nmonth.ToString() + "-0" + Nday.ToString()); CM.IdNo = CardFrist + CM.BrithDay.ToString("yyyyMMdd") + GetCodeForIdNo(); CMlist.Add(CM); } } return CMlist; } /// <summary> /// dd /// </summary> /// <param name="list"></param> private void XiCard(List<int> list) { int i = list.Count; int j; if (i == 0) { return; } while (--i != 0) { Random ran = new Random(); j = ran.Next() % (i + 1); int tmp = list[i]; list[i] = list[j]; list[j] = tmp; } } #endregion
Model 很简单,如下:
public class IdCard { public string IdNo { get; set; } public DateTime BrithDay { get; set; } }
测试如下:
@陈卧龙的博客