国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

js數(shù)組實現(xiàn)權(quán)重概率分配

2019-11-19 15:28:34
字體:
供稿:網(wǎng)友

今天寫了一個js控制頁面輪播的功能,如果僅僅使用隊列很簡單,但是考慮到為每一個頁面分配權(quán)重的是否變的異常復(fù)雜,使用switch和if else也無法解決,于是想到使用js數(shù)組實現(xiàn),思路是將各個輪播的頁面抽象成一個對象,各個對象需要手動指定權(quán)重值,然后組成一個數(shù)組,使用下面封裝的函數(shù),將會根據(jù)各個對象相應(yīng)的權(quán)重概率返回一個對象,代碼如下:

/*** js數(shù)組實現(xiàn)權(quán)重概率分配* @param  Array  arr    js數(shù)組,參數(shù)類型[Object,Object,Object……]* @return  Array        返回一個隨機(jī)元素,概率為其percent/所有percent之和,參數(shù)類型Object* @author  shuiguang*/function weight_rand(arr){  //參數(shù)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;  //下標(biāo)標(biāo)記數(shù)組,按照上面的例子,單倍情況下其組成為[1,2,2,3,4,4]  var index = new Array();  for (i = 0; i < arr.length; i++) {    //判斷元素的權(quán)重,為了實現(xiàn)小數(shù)權(quán)重,先將所有的值放大100倍    percent = 'undefined' != typeof(arr[i].percent) ? parseInt(arr[i].percent*100) : 0;    for (j = 0; j < percent; j++) {      index.push(i);    }    total += percent;  }  //隨機(jī)數(shù)值,其值介于0-5的整數(shù)  var rand = Math.floor(Math.random() * total);  return arr[index[rand]];}

上面的方法雖然可行,可是遇到這樣一個問題:對于一般復(fù)雜的分配情況如1:1:1分配(相對值)可以滿足,如果遇到15%,25%,35%剩余等精確權(quán)重分配(絕對值)無法滿足。因為去計算15%:25%:35%:剩余的比例很是麻煩,于是我將上面的函數(shù)繼續(xù)修改,添加了百分比模式,比如上面的例子,分配了上面明確的百分?jǐn)?shù)之后,剩余的百分比將給最后一個元素,而不用計算最后一個元素占的百分?jǐn)?shù),也不用計算各個元素的比例。代碼如下:

/*** js數(shù)組實現(xiàn)權(quán)重概率分配,支持?jǐn)?shù)字比模式(支持2位小數(shù))和百分比模式(不支持小數(shù),最后一個元素多退少補(bǔ))* @param  Array  arr  js數(shù)組,參數(shù)類型[Object,Object,Object……]* @return  Array      返回一個隨機(jī)元素,概率為其weight/所有weight之和,參數(shù)類型Object* @author  shuiguang*/function weight_rand(arr){	//參數(shù)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%'}];	//求出最大公約數(shù)以計算縮小倍數(shù),perMode為百分比模式	var per;	var maxNum = 0;	var perMode = false;	//自定義Math求最小公約數(shù)方法	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元素對象拷貝仍然會造成浪費,但是使用權(quán)重數(shù)組對應(yīng)關(guān)系更省內(nèi)存	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);	}	//數(shù)字比模式,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下標(biāo)的數(shù)據(jù)塊長度,已優(yōu)化至最小整數(shù)形式減小索引數(shù)組的長度			len = weight_arr[i];			for (j = 0; j < len; j++){				//超過100%跳出,后面的舍棄				if(total >= 100){					break;				}				index.push(i);				total++;			}		}		//使用最后一個元素補(bǔ)齊100%		while(total < 100){			index.push(arr.length-1);			total++;		}	}else{		for (i = 0; i < arr.length; i++) {			//len表示存儲arr下標(biāo)的數(shù)據(jù)塊長度,已優(yōu)化至最小整數(shù)形式減小索引數(shù)組的長度			len = weight_arr[i]/maxNum;			for (j = 0; j < len; j++){				index.push(i);			}			total += len;		}	}	//隨機(jī)數(shù)值,其值為0-11的整數(shù),數(shù)據(jù)塊根據(jù)權(quán)重分塊	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':'數(shù)碼相機(jī)', 'weight':2},	{'id':3, 'prize':'音箱設(shè)備', 'weight':10},	{'id':4, 'prize':'4G優(yōu)盤', 'weight':12},	{'id':5, 'prize':'10Q幣', 'weight':22},	{'id':6, 'prize':'下次沒準(zhǔn)就能中哦', '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 == '數(shù)碼相機(jī)'){		shuma++;	}else if(prize.prize == '音箱設(shè)備'){		yinxiang++;	}else if(prize.prize == '4G優(yōu)盤'){		youpan++;	}else if(prize.prize == '10Q幣'){		qb++;	}else if(prize.prize == '下次沒準(zhǔn)就能中哦'){		xc++;	}}var stop = new Date().getTime();console.log('平板電腦:'+pingban/times+', 數(shù)碼相機(jī):'+shuma/times+', 音箱設(shè)備:'+yinxiang/times+', 4G優(yōu)盤:'+youpan/times+', 10Q幣:'+qb/times+', 下次沒準(zhǔn)就能中哦:'+xc/times);console.log('耗費時間:'+(stop-start)/1000+'秒');

該代碼已經(jīng)通過最大公約數(shù)對下標(biāo)數(shù)組進(jìn)行優(yōu)化,使用數(shù)字比模式已經(jīng)優(yōu)化到最小數(shù)值比例,百分比模式考慮性能消耗暫不支持2位小數(shù)。

寫完js版,于是很輕松改為php版本,經(jīng)過10萬次循環(huán)測試,發(fā)現(xiàn)for循環(huán)比foreach省時間,而非網(wǎng)上傳的foreach比for更快。但是總體來說,js的執(zhí)行速度是php的20倍左右,php的執(zhí)行時間約6秒,js的執(zhí)行時間約為0.346秒。

/*** php數(shù)組實現(xiàn)權(quán)重概率分配,支持?jǐn)?shù)字比模式(支持2位小數(shù))和百分比模式(不支持小數(shù),最后一個元素多退少補(bǔ))* @param  array  $arr  php數(shù)組,參數(shù)類型array(array(),array(),array()……)* @return  array      返回一個隨機(jī)元素,概率為其percent/所有percent之和,參數(shù)類型array()* @author  shuiguang*/function weight_rand($arr){  //參數(shù)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%'));  //求出最大公約數(shù)以計算縮小倍數(shù),perMode為百分比模式  $perMode = false;  $maxNum = 0;  //自定義求最小公約數(shù)方法  $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;  };  //使用傳地址可能會影響后面的結(jié)果,但是使用權(quán)重數(shù)組對應(yīng)關(guān)系更省內(nèi)存  $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);  }  //數(shù)字比模式,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下標(biāo)的數(shù)據(jù)塊長度,已優(yōu)化至最小整數(shù)形式減小索引數(shù)組的長度      $len = $weight_arr[$i];      for ($j = 0; $j < $len; $j++)      {        //超過100%跳出,后面的舍棄        if($total >= 100)        {          break;        }        $index[] = $i;        $total++;      }    }    //使用最后一個元素補(bǔ)齊100%    while($total < 100)    {      $index[] = $arr_len-1;      $total++;    }  }else{    for($i=0; $i<$arr_len; $i++)    {      //len表示存儲arr下標(biāo)的數(shù)據(jù)塊長度,已優(yōu)化至最小整數(shù)形式減小索引數(shù)組的長度      $len = $weight_arr[$i]/$maxNum;      for ($j = 0; $j < $len; $j++)      {        $index[] = $i;      }      $total += $len;    }  }  //隨機(jī)數(shù)值,其值為0-11的整數(shù),數(shù)據(jù)塊根據(jù)權(quán)重分塊  $rand = floor(mt_rand(0, $total));	//修復(fù)php隨機(jī)函數(shù)可以取臨界值造成的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'=>'數(shù)碼相機(jī)', 'weight'=>5),	'2' => array('id'=>3, 'prize'=>'音箱設(shè)備', 'weight'=>10),	'3' => array('id'=>4, 'prize'=>'4G優(yōu)盤', 'weight'=>12),	'4' => array('id'=>5, 'prize'=>'10Q幣', 'weight'=>22),	'5' => array('id'=>6, 'prize'=>'下次沒準(zhǔn)就能中哦', '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版本如果只是使用整數(shù)數(shù)字比模式,完全不用考慮數(shù)字的放大與求最小公倍數(shù)的算法,只需要做簡單的累加即可,可以大大縮短執(zhí)行時間。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 汝南县| 富民县| 商南县| 伽师县| 滕州市| 项城市| 临汾市| 华坪县| 分宜县| 和田县| 巩留县| 墨玉县| 海晏县| 炎陵县| 庐江县| 襄汾县| 皋兰县| 崇明县| 汾西县| 池州市| 澄迈县| 秦皇岛市| 六盘水市| 日照市| 横山县| 宽城| 和平区| 佛学| 五寨县| 汪清县| 连江县| 阜宁县| 阿拉善右旗| 富民县| 辉县市| 平凉市| 同江市| 伊金霍洛旗| 正安县| 健康| 胶州市|