假设有如下一个数组
- $list = array("A" => 5, "B" => 10, "C" => 15, "D" => 20, "E" => 50);
表示随机ABCDE,取到A的概率是5%,B为10%,C为15%,D为20%,E为50%。
思路很简单,画一根数轴,长度是ABCDE的权值的总和,按照他们的权值,分割这个数轴。
然后随机取数轴上的一点,落在哪个区间,就取哪个值。
具体算法如下
- function GetRandom() {
- $list = array("A" => 5, "B" => 10, "C" => 15, "D" => 20, "E" => 50);
- $sum = 0;
- $listPoint = array(0);//这个数组记录了每个切割点的值,就是记录了数轴上,5,15,30,50,100的值。
- foreach ($list as $key => $value) {
- $sum+=$value;//计算出权值的总和
- array_push($listPoint, $sum);//把分割点放到数组中
- }
- $num = rand(0, $sum);//取0到sum之间一个随机值
- //echo $num . ":";
- for ($i = 0; $i < count($listPoint) - 1; $i++)
- {
- if ($num >= $listPoint[$i] && $num <= $listPoint[$i + 1]) //判断随机值落在哪个范围内
- {
- $elem = array_slice($list, $i, 1);
- return key($elem); //第i项的值
- }
- }
- echo "can't be here";
- }
测试代码,随机取100次,看看各个字母出现的次数。
- $a = 0;
- $b = 0;
- $c = 0;
- $d = 0;
- $e = 0;
- for ($i = 0; $i < 100; $i++) {
- $char = GetRandom();
- echo "$char ";
- switch ($char) {
- case "A":
- $a++;
- break;
- case "B":
- $b++;
- break;
- case "C":
- $c++;
- break;
- case "D":
- $d++;
- break;
- case "E":
- $e++;
- break;
- }
- }
- echo "A:$a<br>";
- echo "B:$b<br>";
- echo "C:$c<br>";
- echo "D:$d<br>";
- echo "E:$e<br>";
- die(0);
得到的结果勉强也能接受。