时间:2021-07-01 10:21:17 帮助过:16人阅读
上面的方法虽然可行,可是遇到这样一个问题:对于一般复杂的分配情况如1:1:1分配(相对值)可以满足,如果遇到15%,25%,35%剩余等精确权重分配(绝对值)无法满足。因为去计算15%:25%:35%:剩余的比例很是麻烦,于是我将上面的函数继续修改,添加了百分比模式,比如上面的例子,分配了上面明确的百分数之后,剩余的百分比将给最后一个元素,而不用计算最后一个元素占的百分数,也不用计算各个元素的比例。代码如下:
该代码已经通过最大公约数对下标数组进行优化,使用数字比模式已经优化到最小数值比例,百分比模式考虑性能消耗暂不支持2位小数。
写完js版,于是很轻松改为php版本,经过10万次循环测试,发现for循环比foreach省时间,而非网上传的foreach比for更快。但是总体来说,js的执行速度是php的20倍左右,php的执行时间约6秒,js的执行时间约为0.346秒。
/** * php数组实现权重概率分配,支持数字比模式(支持2位小数)和百分比模式(不支持小数,最后一个元素多退少补) * @param array $arr php数组,参数类型array(array(),array(),array()……) * @return array 返回一个随机元素,概率为其percent/所有percent之和,参数类型array() * @author shuiguang */ function weight_rand($arr) { //参数arr元素必须含有percent属性,参考如下所示 //$arr=array(array('name'=>'1','weight'=>1.5),array('name'=>'2','weight'=>1.5),array('name'=>'3','weight'=>1.5)); //$arr=array(array('name'=>'1','weight'=>'15%'),array('name'=>'2','weight'=>'25%'),array('name'=>'3','weight'=>'35%')); //求出最大公约数以计算缩小倍数,perMode为百分比模式 $perMode = false; $maxNum = 0; //自定义求最小公约数方法 $gcd = function($a, $b) { $min = min($a, $b); $max = max($a, $b); $result = 1; if($a === 0 || $b === 0) { return $max; } for($i=$min; $i>=1; $i--) { if($min % $i === 0 && $max % $i === 0) { $result = $i; break; } } return $result; }; //使用传地址可能会影响后面的结果,但是使用权重数组对应关系更省内存 $weight_arr = array(); $arr_len = count($arr); for($i=0; $i<$arr_len; $i++) { if(isset($arr[$i]['weight'])) { if(strpos($arr[$i]['weight'], '%') !== false) { $per = floor(str_replace('%', '', $arr[$i]['weight'])); $perMode = true; }else{ $per = floor($arr[$i]['weight']*100); } }else{ $per = 0; } $weight_arr[$i] = $per; $maxNum = call_user_func($gcd, $maxNum, $per); } //数字比模式,3:5:7,其组成[0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2] //百分比模式,元素所占百分比为15%,25%,35% $index = array(); $total = 0; if($perMode) { for($i=0; $i<$arr_len; $i++) { //$len表示存储$arr下标的数据块长度,已优化至最小整数形式减小索引数组的长度 $len = $weight_arr[$i]; for ($j = 0; $j < $len; $j++) { //超过100%跳出,后面的舍弃 if($total >= 100) { break; } $index[] = $i; $total++; } } //使用最后一个元素补齐100% while($total < 100) { $index[] = $arr_len-1; $total++; } }else{ for($i=0; $i<$arr_len; $i++) { //len表示存储arr下标的数据块长度,已优化至最小整数形式减小索引数组的长度 $len = $weight_arr[$i]/$maxNum; for ($j = 0; $j < $len; $j++) { $index[] = $i; } $total += $len; } } //随机数值,其值为0-11的整数,数据块根据权重分块 $rand = floor(mt_rand(0, $total)); //修复php随机函数可以取临界值造成的bug $rand = $rand == $total ? $total-1 : $rand; return $arr[$index[$rand]]; } $arr=array(array('name'=>'1','weight'=>1.5),array('name'=>'2','weight'=>1.5),array('name'=>'3','weight'=>1.5)); p(weight_rand($arr)); $arr=array(array('name'=>'1','weight'=>'15%'),array('name'=>'2','weight'=>'25%'),array('name'=>'3','weight'=>'35%')); p(weight_rand($arr)); $prize_arr = array( '0' => array('id'=>1, 'prize'=>'平板电脑', 'weight'=>1), '1' => array('id'=>2, 'prize'=>'数码相机', 'weight'=>5), '2' => array('id'=>3, 'prize'=>'音箱设备', 'weight'=>10), '3' => array('id'=>4, 'prize'=>'4G优盘', 'weight'=>12), '4' => array('id'=>5, 'prize'=>'10Q币', 'weight'=>22), '5' => array('id'=>6, 'prize'=>'下次没准就能中哦', 'weight'=>50), ); $start = time(); $result = array(); $times = 100000; for($i=0; $i<$times; $i++) { $row = weight_rand($prize_arr); if(array_key_exists($row['prize'], $result)) { $result[$row['prize']] ++; }else{ $result[$row['prize']] = 1; } } $cost = time() - $start; p($result); p('耗费时间:'.$cost.'秒'); function p($var) { echo "<pre>"; if($var === false) { echo 'false'; }else if($var === ''){ print_r("''"); }else{ print_r($var); } echo "</pre>"; }
php版本如果只是使用整数数字比模式,完全不用考虑数字的放大与求最小公倍数的算法,只需要做简单的累加即可,可以大大缩短执行时间。
相关推荐:
PHP如何实现round robin权重轮循算法
css的层叠性与权重的讲解
round robin权重轮循算法php实现代码
以上就是js数组实现权重概率分配的代码分享的详细内容,更多请关注Gxl网其它相关文章!