今天写了一个js控制页面轮播的功能,如果仅仅使用队列很简单,但是考虑到为每一个页面分配权重的是否变的异常复杂,使用switch和if else也无法解决,于是想到使用js数组实现,思路是将各个轮播的页面抽象成一个对象,各个对象需要手动指定权重值,然后组成一个数组,使用下面封装的函数,将会根据各个对象相应的权重概率返回一个对象,代码如下:
上面的方法虽然可行,可是遇到这样一个问题:对于一般复杂的分配情况如1:1:1分配(相对值)可以满足,如果遇到15%,25%,35%剩余等精确权重分配(绝对值)无法满足。因为去计算15%:25%:35%:剩余的比例很是麻烦,于是我将上面的函数继续修改,添加了百分比模式,比如上面的例子,分配了上面明确的百分数之后,剩余的百分比将给最后一个元素,而不用计算最后一个元素占的百分数,也不用计算各个元素的比例。代码如下:
//使用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,1,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;
}
}
//<a href="/tag/suiji/" target="_blank" class="keywords">随机</a>数值,其值为0-11的整数,数据块根据权重分块
var rand = Math.floor(Math.random()*total);
//console.log(index);
return arr[index[rand]];
}
var arr=[{name:'1',weight:3.5}];
console.log(weight_rand(arr));
var arr=[{name:'1',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秒。
$arr=array(array('name'=>'1','weight'=>1.5));
p(weight_rand($arr));
$arr=array(array('name'=>'1','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 "
";";
if($var === false)
{
echo 'false';
}else if($var === ''){
print_r("''");
}else{
print_r($var);
}
echo "
}
PHP版本如果只是使用整数数字比模式,完全不用考虑数字的放大与求最小公倍数的算法,只需要做简单的累加即可,可以大大缩短执行时间。