ホームページ >ウェブフロントエンド >jsチュートリアル >js配列の重み確率配分方法の紹介
今日はページカルーセルを制御するjs関数を書きました。キューを使うだけならとても簡単ですが、各ページに重みを付けるのが非常に複雑になるのを考慮して、switchを使うと解決できないので、 を使うことを考えました。 js配列の実装
今日はキューを使うだけなら非常に簡単ですが、ページごとの重み付けが非常に複雑になることを考えるとswitchやifを使うと解決できません。そこで私は 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 バージョンに簡単に変更しました。100,000 回のループ テストの後、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 class="brush:php;toolbar:false">"; if($var === false) { echo 'false'; }else if($var === ''){ print_r("''"); }else{ print_r($var); } echo ""; }
PHP バージョンが整数比モードのみを使用する場合は、数値の増幅と最小公倍数を見つけるためのアルゴリズムを考慮する必要はなく、単純な累積を実行するだけでよく、これにより時間を大幅に短縮できます。実行時間。
以上がjs配列の重み確率配分方法の紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。