目录
最复杂的,一个list中有a,b两个数据,a按照70%概率返回而b按30%返回,就这样写
背景
在项目开发过程中,经常会使用到系统里随机数的功能,顾名思义,就是需要获取一定概率下的结果。
比如需要一个集合中随机抽取其中某个或者某几个元素;又或者需要以一定概率值返回一个bool值(以38%的概率返回True)等;以及需要产生连续的随机数等需求存在一定的普遍性。
用法
获取随机数,确保同时调用不会重复
RandomTask.Next(5);
从一个列表中,随机获取其中某个值
List<string> lsTest = new List<string>
{
"1","2","3","4","5"
};
string randomValue = RandomTask.PickOne(lsTest);
Console.WriteLine(randomValue);
从一个列表中,随机获取其中多个值
List<string> someRandomValue = RandomTask.PickAny(lsTest, 3);
Console.WriteLine(string.Join(",", someRandomValue));
想按某个概率返回bool值,可以这么写
bool is30Per = RandomTask.PickBoolByProp(0.3);
Console.WriteLine(is30Per);
最复杂的,一个list中有a,b两个数据,a按照70%概率返回而b按30%返回,就这样写
Dictionary<string, double> lsTestAB = new Dictionary<string, double>
{
{"A",0.7 },
{ "B",0.3}
};
string aOrb = RandomTask.PickOneByProb(lsTestAB);
Console.WriteLine(aOrb);
完整源码
public static class RandomTask
{
private static readonly Random _random = new Random();
public static int Next()
{
lock (_random)
{
return _random.Next();
}
}
public static int Next(int max)
{
lock (_random)
{
return _random.Next(max);
}
}
public static int Next(int min, int max)
{
lock (_random)
{
return _random.Next(min, max);
}
}
/// <summary>
/// 按概率获取
/// </summary>
/// <param name="trueProp"></param>
/// <returns></returns>
public static bool PickBoolByProp(double trueProp = 1)
{
if (trueProp > 1)
{
trueProp = 1;
}
if (trueProp < 0)
{
trueProp = 0;
}
Dictionary<bool, double> wt = new Dictionary<bool, double>
{
{ true , trueProp },
{ false , 1 - trueProp }
};
return wt.PickOneByProb();
}
/// <summary>
/// 按指定概率获取随机结果
/// </summary>
/// <param name="sourceDic">a 0.8 b 0.1 c 0.1</param>
/// <returns>随机结果 [a,b,c]</returns>
public static T PickOneByProb<T>(this Dictionary<T, double> sourceDic)
{
if (sourceDic == null || !sourceDic.Any())
{
return default(T);
}
int seed = (int)(10 / (sourceDic.Values.Where(c => c > 0).Min()));
int maxValue = sourceDic.Values.Aggregate(0, (current, d) => current + (int)(seed * d));
int rNum = Next(maxValue);
int tem = 0;
foreach (KeyValuePair<T, double> item in sourceDic)
{
tem += (int)(item.Value * seed);
if (tem > rNum)
{
return item.Key;
}
}
return default(T);
}
/// <summary>
/// 随机从List中获取一项
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <returns></returns>
public static T PickOne<T>(this List<T> source)
{
if (source == null || !source.Any())
{
return default(T);
}
return source[Next(source.Count)];
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="c"></param>
/// <returns></returns>
public static List<T> PickAny<T>(this List<T> source, int c)
{
if (source == null || !source.Any())
{
return default(List<T>);
}
if (source.Count <= c)
{
return source;
}
List<T> ls = new List<T>();
for (int i = 0; i < c; i++)
{
var t = source.PickOne();
if (!ls.Contains(t))
{
ls.Add(t);
}
}
return ls;
}
}