老生常談,還是那三句話:
學歷代表你的過去,能力代表你的現在,學習代表你的將來
十年河東,十年河西,莫欺少年窮
學無止境,精益求精
問題描述:很多時候我們可能需要在極短的時間內生成大量的隨機數,但是你可能會發現生成了很多重復的隨機數。並不是你所希望生成大量不同的數,或者說相同的數極少。
分析原因: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; } }
測試如下:
@陳卧龍的博客