注:本文思路已經應用於“飛梭TXT文本數據處理百寶箱”中,有興趣的朋友可以下載試用。
我們知道,如果需要批量生成海量無重復的隨機數據是個很麻煩的事情。如果每次生成都要和之前生成的數據進行比對的話,那效率會隨着數據量的增大而越來越低,最后不堪忍受。今天介紹一種另類的思路,可以高效的做到隨機數據無重復。
分析:所謂隨機數據,就是在某個設定的區間內隨機提取一批數據出來。那么我們可以變通的思考一下:我們可不可以將此設定的數據區間A按照所需的數據量N分成N個小的數據區間B,如果這樣的話,我們只需要每次從數據區間B中取一個隨機值,並且不需要驗證是否重復,就可以很容易的得到N個唯一的數據。而這些數據集也是隨機的,只不過是稍微帶有一定的均布特性。
這里有個問題,按照以上的思路取出的數據雖然是隨機的,但是還是按照從小到大的順序排列,這是個遺憾。解決辦法:獲取到隨機數據集合后,使用洗牌算法對數據進行打亂處理。
實現代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DataGenerator.DataObject
{
public class RandomData : DynamicDataBase
{
private Random m_ro;
private List< string> m_codes;
private long m_lastNum;
private long m_span;
private char m_padStr;
public override string GetDataByIndex( int index)
{
return m_codes[index];
}
public override void Reset( int count)
{
// 初始化m_fromNum;根據生成數量設置m_span值
try
{
// m_fromNum = 0;
// char[] cs = FromStr.ToArray();
// int idx;
// for (int i = 0; i < cs.Length; i++)
// {
// idx = CharList.IndexOf(cs[i]);
// m_fromNum += Convert.ToInt32(idx * Math.Pow(CharList.Length, cs.Length - i - 1));
// }
// m_lastNum = m_fromNum - 1;
m_lastNum = - 1L;
// 測試最后一個生成的最小數值是否越界
int idx = count - 1;
if (idx.ToString().Length > Length)
throw new Exception( " 數量超出長度界限 ");
// 該數據長度下的最大值
long maxV = Math.Pow(CharList.Length, Length) - 1 > long.MaxValue ? long.MaxValue : ( long)(Math.Pow(CharList.Length, Length) - 1);
if (maxV < idx)
throw new Exception();
// m_span = (maxV - idx) / count;
// 數據余量初始化
m_span = maxV - idx;
// 補齊字符初始化
m_padStr = CharList.ToCharArray()[ 0];
// 初始化數據集合
m_codes = null;
}
catch
{
throw new Exception( " 隨機碼起始值或生成數量越界!嘗試調整生成數量、數據長度、起始字符串等設置后再試。 ");
}
}
public void PrepareCodes( int count)
{
// m_codes = new List<string>(count);
string[] source = new string[count];
for ( int i = 0; i < count; i++)
{
source[i] = GenerateCode(i, count);
}
m_codes = new List< string>(Shuffle< string>(source));
source = null;
}
private IEnumerable<T> Shuffle<T>(IEnumerable<T> source)
{
m_ro = new Random();
T[] elements = source.ToArray();
for ( int i = elements.Length - 1; i > 0; i--)
{
int swapIndex = m_ro.Next(i + 1);
yield return elements[swapIndex];
elements[swapIndex] = elements[i];
}
yield return elements[ 0];
}
private string GenerateCode( int index, int count)
{
long num2 = DateTime.Now.Ticks + index;
m_ro = new Random((( int)((( ulong)num2) & 0xffffffffL)) | (( int)(num2 >> index)));
// 本次可以使用的最大余量
long s = m_span / (count - index);
// 本次使用的余量
s = m_ro.Next(s + 1 > int.MaxValue ? int.MaxValue : ( int)(s + 1));
// 余量減少
m_span -= s;
// 記錄最近一次使用的數值
m_lastNum += 1 + s;
long position = m_lastNum;
StringBuilder sb = new StringBuilder();
int yushu = 0;
while (position >= CharList.Length)
{
yushu = ( int)(position % CharList.Length);
sb.Append(CharList.Substring(yushu, 1));
position = (position - yushu) / CharList.Length;
}
sb.Append(CharList.Substring(( int)position, 1));
return ( new string(sb.ToString().Reverse< char>().ToArray())).PadLeft(Length, m_padStr);
}
public void Dispose()
{
if(m_ro != null)
m_ro = null;
if (m_codes != null)
m_codes = null;
}
public override string ToString()
{
return string.Format( " <字符集:{0},長度:{1},起始:{2}> ", CharList, Length, FromStr);
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DataGenerator.DataObject
{
public class RandomData : DynamicDataBase
{
private Random m_ro;
private List< string> m_codes;
private long m_lastNum;
private long m_span;
private char m_padStr;
public override string GetDataByIndex( int index)
{
return m_codes[index];
}
public override void Reset( int count)
{
// 初始化m_fromNum;根據生成數量設置m_span值
try
{
// m_fromNum = 0;
// char[] cs = FromStr.ToArray();
// int idx;
// for (int i = 0; i < cs.Length; i++)
// {
// idx = CharList.IndexOf(cs[i]);
// m_fromNum += Convert.ToInt32(idx * Math.Pow(CharList.Length, cs.Length - i - 1));
// }
// m_lastNum = m_fromNum - 1;
m_lastNum = - 1L;
// 測試最后一個生成的最小數值是否越界
int idx = count - 1;
if (idx.ToString().Length > Length)
throw new Exception( " 數量超出長度界限 ");
// 該數據長度下的最大值
long maxV = Math.Pow(CharList.Length, Length) - 1 > long.MaxValue ? long.MaxValue : ( long)(Math.Pow(CharList.Length, Length) - 1);
if (maxV < idx)
throw new Exception();
// m_span = (maxV - idx) / count;
// 數據余量初始化
m_span = maxV - idx;
// 補齊字符初始化
m_padStr = CharList.ToCharArray()[ 0];
// 初始化數據集合
m_codes = null;
}
catch
{
throw new Exception( " 隨機碼起始值或生成數量越界!嘗試調整生成數量、數據長度、起始字符串等設置后再試。 ");
}
}
public void PrepareCodes( int count)
{
// m_codes = new List<string>(count);
string[] source = new string[count];
for ( int i = 0; i < count; i++)
{
source[i] = GenerateCode(i, count);
}
m_codes = new List< string>(Shuffle< string>(source));
source = null;
}
private IEnumerable<T> Shuffle<T>(IEnumerable<T> source)
{
m_ro = new Random();
T[] elements = source.ToArray();
for ( int i = elements.Length - 1; i > 0; i--)
{
int swapIndex = m_ro.Next(i + 1);
yield return elements[swapIndex];
elements[swapIndex] = elements[i];
}
yield return elements[ 0];
}
private string GenerateCode( int index, int count)
{
long num2 = DateTime.Now.Ticks + index;
m_ro = new Random((( int)((( ulong)num2) & 0xffffffffL)) | (( int)(num2 >> index)));
// 本次可以使用的最大余量
long s = m_span / (count - index);
// 本次使用的余量
s = m_ro.Next(s + 1 > int.MaxValue ? int.MaxValue : ( int)(s + 1));
// 余量減少
m_span -= s;
// 記錄最近一次使用的數值
m_lastNum += 1 + s;
long position = m_lastNum;
StringBuilder sb = new StringBuilder();
int yushu = 0;
while (position >= CharList.Length)
{
yushu = ( int)(position % CharList.Length);
sb.Append(CharList.Substring(yushu, 1));
position = (position - yushu) / CharList.Length;
}
sb.Append(CharList.Substring(( int)position, 1));
return ( new string(sb.ToString().Reverse< char>().ToArray())).PadLeft(Length, m_padStr);
}
public void Dispose()
{
if(m_ro != null)
m_ro = null;
if (m_codes != null)
m_codes = null;
}
public override string ToString()
{
return string.Format( " <字符集:{0},長度:{1},起始:{2}> ", CharList, Length, FromStr);
}
}
}