温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

js中数组实现权重概率分配的示例分析

发布时间:2021-08-02 10:42:05 来源:亿速云 阅读:210 作者:小新 栏目:web开发

小编给大家分享一下js中数组实现权重概率分配的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

代码如下:

/** * js数组实现权重概率分配 * @param  Array  arr    js数组,参数类型[Object,Object,Object……] * @return  Array        返回一个随机元素,概率为其percent/所有percent之和,参数类型Object * @author  shuiguang */ function weight_rand(arr){   //参数arr元素必须含有percent属性,参考如下所示   /*   var arr = [{       name : '1',       percent : 1     }, {       name : '2',       percent : 2     }, {       name : '3',       percent : 1     }, {       name : '4',       percent : 2     }   ];   */   var total = 0;   var i, j, percent;   //下标标记数组,按照上面的例子,单倍情况下其组成为[1,2,2,3,4,4]   var index = new Array();   for (i = 0; i < arr.length; i++) {     //判断元素的权重,为了实现小数权重,先将所有的值放大100倍     percent = 'undefined' != typeof(arr[i].percent) ? parseInt(arr[i].percent*100) : 0;     for (j = 0; j < percent; j++) {       index.push(i);     }     total += percent;   }   //随机数值,其值介于0-5的整数   var rand = Math.floor(Math.random() * total);   return arr[index[rand]]; }

上面的方法虽然可行,可是遇到这样一个问题:对于一般复杂的分配情况如1:1:1分配(相对值)可以满足,如果遇到15%,25%,35%剩余等精确权重分配(绝对值)无法满足。因为去计算15%:25%:35%:剩余的比例很是麻烦,于是我将上面的函数继续修改,添加了百分比模式,比如上面的例子,分配了上面明确的百分数之后,剩余的百分比将给最后一个元素,而不用计算最后一个元素占的百分数,也不用计算各个元素的比例。代码如下:

/** * js数组实现权重概率分配,支持数字比模式(支持2位小数)和百分比模式(不支持小数,最后一个元素多退少补) * @param  Array  arr  js数组,参数类型[Object,Object,Object……] * @return  Array      返回一个随机元素,概率为其weight/所有weight之和,参数类型Object * @author  shuiguang */ function weight_rand(arr){	//参数arr元素必须含有weight属性,参考如下所示	//var arr=[{name:'1',weight:1.5},{name:'2',weight:2.5},{name:'3',weight:3.5}];	//var arr=[{name:'1',weight:'15%'},{name:'2',weight:'25%'},{name:'3',weight:'35%'}];	//求出最大公约数以计算缩小倍数,perMode为百分比模式	var per;	var maxNum = 0;	var perMode = false;	//自定义Math求最小公约数方法	Math.gcd = function(a,b){	var min = Math.min(a,b);	var max = Math.max(a,b);	var result = 1;	if(a === 0 || b===0){	return max;	}	for(var i=min; i>=1; i--){	if(min % i === 0 && max % i === 0){	result = i;	break;	}	}	return result;	};	//使用clone元素对象拷贝仍然会造成浪费,但是使用权重数组对应关系更省内存	var weight_arr = new Array();	for (i = 0; i < arr.length; i++) {	if('undefined' != typeof(arr[i].weight))	{	if(arr[i].weight.toString().indexOf('%') !== -1) {	per = Math.floor(arr[i].weight.toString().replace('%',''));	perMode = true;	}else{	per = Math.floor(arr[i].weight*100);	}	}else{	per = 0;	}	weight_arr[i] = per;	maxNum = Math.gcd(maxNum, per);	}	//数字比模式,3:5:7,其组成[0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2]	//百分比模式,元素所占百分比为15%,25%,35%	var index = new Array();	var total = 0;	var len = 0;	if(perMode){	for (i = 0; i < arr.length; i++) {	//len表示存储arr下标的数据块长度,已优化至最小整数形式减小索引数组的长度	len = weight_arr[i];	for (j = 0; j < len; j++){	//超过100%跳出,后面的舍弃	if(total >= 100){	break;	}	index.push(i);	total++;	}	}	//使用最后一个元素补齐100%	while(total < 100){	index.push(arr.length-1);	total++;	}	}else{	for (i = 0; i < arr.length; i++) {	//len表示存储arr下标的数据块长度,已优化至最小整数形式减小索引数组的长度	len = weight_arr[i]/maxNum;	for (j = 0; j < len; j++){	index.push(i);	}	total += len;	}	}	//随机数值,其值为0-11的整数,数据块根据权重分块	var rand = Math.floor(Math.random()*total);	//console.log(index);	return arr[index[rand]]; } var arr=[{name:'1',weight:1.5},{name:'2',weight:2.5},{name:'3',weight:3.5}]; console.log(weight_rand(arr)); var arr=[{name:'1',weight:'15%'},{name:'2',weight:'25%'},{name:'3',weight:'35%'}]; console.log(weight_rand(arr)); var prize_arr = [	{'id':1, 'prize':'平板电脑', 'weight':1},	{'id':2, 'prize':'数码相机', 'weight':2},	{'id':3, 'prize':'音箱设备', 'weight':10},	{'id':4, 'prize':'4G优盘', 'weight':12},	{'id':5, 'prize':'10Q币', 'weight':22},	{'id':6, 'prize':'下次没准就能中哦', 'weight':50}     ]; var times = 100000; var prize; var pingban = 0; var shuma = 0; var yinxiang = 0; var youpan = 0; var qb = 0; var xc = 0; var start = new Date().getTime(); for($i=0; $i<times; $i++){	prize = weight_rand(prize_arr);	if(prize.prize == '平板电脑')	{	pingban++;	}else if(prize.prize == '数码相机'){	shuma++;	}else if(prize.prize == '音箱设备'){	yinxiang++;	}else if(prize.prize == '4G优盘'){	youpan++;	}else if(prize.prize == '10Q币'){	qb++;	}else if(prize.prize == '下次没准就能中哦'){	xc++;	} } var stop = new Date().getTime(); console.log('平板电脑:'+pingban/times+', 数码相机:'+shuma/times+', 音箱设备:'+yinxiang/times+', 4G优盘:'+youpan/times+', 10Q币:'+qb/times+', 下次没准就能中哦:'+xc/times); console.log('耗费时间:'+(stop-start)/1000+'秒');

该代码已经通过最大公约数对下标数组进行优化,使用数字比模式已经优化到最小数值比例,百分比模式考虑性能消耗暂不支持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版本如果只是使用整数数字比模式,完全不用考虑数字的放大与求最小公倍数的算法,只需要做简单的累加即可,可以大大缩短执行时间。

看完了这篇文章,相信你对“js中数组实现权重概率分配的示例分析”有了一定的了解,如果想了解更多相关知识,欢迎关注亿速云行业资讯频道,感谢各位的阅读!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

js
AI