Heim >Web-Frontend >js-Tutorial >Einführung in die Gewichtswahrscheinlichkeitszuordnungsmethode des js-Arrays

Einführung in die Gewichtswahrscheinlichkeitszuordnungsmethode des js-Arrays

巴扎黑
巴扎黑Original
2017-09-13 09:19:561614Durchsuche

Heute habe ich eine js-Funktion geschrieben, um das Seitenkarussell zu steuern. Es ist sehr einfach, wenn man nur die Warteschlange verwendet, aber wenn man bedenkt, dass das Zuweisen von Gewichtung zu jeder Seite extrem kompliziert wird, kann es nicht mit dem Schalter gelöst werden, und wenn nicht, dachte ich der Verwendung von js-Array-Implementierung

Heute habe ich eine js-Funktion zur Steuerung des Seitenkarussells geschrieben. Es ist sehr einfach, wenn Sie nur die Warteschlange verwenden, aber wenn man bedenkt, ob das Zuweisen von Gewicht zu jeder Seite extrem kompliziert wird, verwenden Sie den Schalter und wenn nicht Kann es auch nicht lösen, ich habe darüber nachgedacht, es mit einem js-Array zu implementieren. Die Idee besteht darin, jede Karussellseite in ein Objekt zu abstrahieren und dann ein Array zu bilden Im Folgenden wird die Wahrscheinlichkeit auf der Grundlage des entsprechenden Gewichts jedes Objekts zurückgegeben. Der Code lautet wie folgt:


/**
* 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 = &#39;undefined&#39; != 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]];
}

Obwohl die obige Methode machbar ist, Es tritt ein solches Problem auf: Im Allgemeinen kann eine komplexe Zuordnungssituation wie 1:1:1 (relativer Wert) erfüllt werden, aber wenn Sie auf 15 %, 25 %, 35 % verbleibende und andere genaue Gewichtsverteilungen (absoluter Wert) stoßen, es kann nicht befriedigt werden. Da es sehr mühsam ist, das verbleibende Verhältnis von 15 %:25 %:35 % zu berechnen, habe ich die obige Funktion weiter modifiziert und einen Prozentmodus hinzugefügt. Im obigen Beispiel wurde beispielsweise der verbleibende klare Prozentsatz zugewiesen Prozentsatz wird sein Geben Sie das letzte Element an, ohne den Prozentsatz des letzten Elements oder den Anteil jedes Elements zu berechnen. Der Code lautet wie folgt:


/**
* 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:&#39;1&#39;,weight:1.5},{name:&#39;2&#39;,weight:2.5},{name:&#39;3&#39;,weight:3.5}];
	//var arr=[{name:&#39;1&#39;,weight:&#39;15%&#39;},{name:&#39;2&#39;,weight:&#39;25%&#39;},{name:&#39;3&#39;,weight:&#39;35%&#39;}];
	//求出最大公约数以计算缩小倍数,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(&#39;undefined&#39; != typeof(arr[i].weight))
		{
			if(arr[i].weight.toString().indexOf(&#39;%&#39;) !== -1) {
				per = Math.floor(arr[i].weight.toString().replace(&#39;%&#39;,&#39;&#39;));
				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:&#39;1&#39;,weight:1.5},{name:&#39;2&#39;,weight:2.5},{name:&#39;3&#39;,weight:3.5}];
console.log(weight_rand(arr));
var arr=[{name:&#39;1&#39;,weight:&#39;15%&#39;},{name:&#39;2&#39;,weight:&#39;25%&#39;},{name:&#39;3&#39;,weight:&#39;35%&#39;}];
console.log(weight_rand(arr));
var prize_arr = [
	{&#39;id&#39;:1, &#39;prize&#39;:&#39;平板电脑&#39;, &#39;weight&#39;:1},
	{&#39;id&#39;:2, &#39;prize&#39;:&#39;数码相机&#39;, &#39;weight&#39;:2},
	{&#39;id&#39;:3, &#39;prize&#39;:&#39;音箱设备&#39;, &#39;weight&#39;:10},
	{&#39;id&#39;:4, &#39;prize&#39;:&#39;4G优盘&#39;, &#39;weight&#39;:12},
	{&#39;id&#39;:5, &#39;prize&#39;:&#39;10Q币&#39;, &#39;weight&#39;:22},
	{&#39;id&#39;:6, &#39;prize&#39;:&#39;下次没准就能中哦&#39;, &#39;weight&#39;: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 == &#39;平板电脑&#39;)
	{
		pingban++;
	}else if(prize.prize == &#39;数码相机&#39;){
		shuma++;
	}else if(prize.prize == &#39;音箱设备&#39;){
		yinxiang++;
	}else if(prize.prize == &#39;4G优盘&#39;){
		youpan++;
	}else if(prize.prize == &#39;10Q币&#39;){
		qb++;
	}else if(prize.prize == &#39;下次没准就能中哦&#39;){
		xc++;
	}
}

var stop = new Date().getTime();
console.log(&#39;平板电脑:&#39;+pingban/times+&#39;, 数码相机:&#39;+shuma/times+&#39;, 音箱设备:&#39;+yinxiang/times+&#39;, 4G优盘:&#39;+youpan/times+&#39;, 10Q币:&#39;+qb/times+&#39;, 下次没准就能中哦:&#39;+xc/times);
console.log(&#39;耗费时间:&#39;+(stop-start)/1000+&#39;秒&#39;);

Dieser Code wurde für das Indexarray durch den größten gemeinsamen Nenner optimiert und auf den minimalen numerischen Wert optimiert Verhältnis, Prozentsatz im numerischen Verhältnismodus. Aufgrund des Leistungsverbrauchs unterstützt der Modus derzeit keine 2 Dezimalstellen.

Nachdem ich die js-Version geschrieben hatte, konnte ich sie problemlos auf die PHP-Version umstellen. Nach 100.000 Schleifentests stellte ich fest, dass die for-Schleife Zeit spart als foreach und das aus dem Internet hochgeladene foreach schneller ist als for. Aber im Allgemeinen ist die Ausführungsgeschwindigkeit von js etwa 20-mal so hoch wie die von PHP. Die Ausführungszeit von PHP beträgt etwa 6 Sekunden und die Ausführungszeit von js beträgt etwa 0,346 Sekunden.


/**
* 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(&#39;name&#39;=>&#39;1&#39;,&#39;weight&#39;=>1.5),array(&#39;name&#39;=>&#39;2&#39;,&#39;weight&#39;=>1.5),array(&#39;name&#39;=>&#39;3&#39;,&#39;weight&#39;=>1.5));
  //$arr=array(array(&#39;name&#39;=>&#39;1&#39;,&#39;weight&#39;=>&#39;15%&#39;),array(&#39;name&#39;=>&#39;2&#39;,&#39;weight&#39;=>&#39;25%&#39;),array(&#39;name&#39;=>&#39;3&#39;,&#39;weight&#39;=>&#39;35%&#39;));
  //求出最大公约数以计算缩小倍数,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][&#39;weight&#39;]))
    {
      if(strpos($arr[$i][&#39;weight&#39;], &#39;%&#39;) !== false)
      {
        $per = floor(str_replace(&#39;%&#39;, &#39;&#39;, $arr[$i][&#39;weight&#39;]));
        $perMode = true;
      }else{
        $per = floor($arr[$i][&#39;weight&#39;]*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(&#39;name&#39;=>&#39;1&#39;,&#39;weight&#39;=>1.5),array(&#39;name&#39;=>&#39;2&#39;,&#39;weight&#39;=>1.5),array(&#39;name&#39;=>&#39;3&#39;,&#39;weight&#39;=>1.5));
p(weight_rand($arr));
$arr=array(array(&#39;name&#39;=>&#39;1&#39;,&#39;weight&#39;=>&#39;15%&#39;),array(&#39;name&#39;=>&#39;2&#39;,&#39;weight&#39;=>&#39;25%&#39;),array(&#39;name&#39;=>&#39;3&#39;,&#39;weight&#39;=>&#39;35%&#39;));
p(weight_rand($arr));

$prize_arr = array(
	&#39;0&#39; => array(&#39;id&#39;=>1, &#39;prize&#39;=>&#39;平板电脑&#39;, &#39;weight&#39;=>1),
	&#39;1&#39; => array(&#39;id&#39;=>2, &#39;prize&#39;=>&#39;数码相机&#39;, &#39;weight&#39;=>5),
	&#39;2&#39; => array(&#39;id&#39;=>3, &#39;prize&#39;=>&#39;音箱设备&#39;, &#39;weight&#39;=>10),
	&#39;3&#39; => array(&#39;id&#39;=>4, &#39;prize&#39;=>&#39;4G优盘&#39;, &#39;weight&#39;=>12),
	&#39;4&#39; => array(&#39;id&#39;=>5, &#39;prize&#39;=>&#39;10Q币&#39;, &#39;weight&#39;=>22),
	&#39;5&#39; => array(&#39;id&#39;=>6, &#39;prize&#39;=>&#39;下次没准就能中哦&#39;, &#39;weight&#39;=>50),
);

$start = time();
$result = array();
$times = 100000;
for($i=0; $i<$times; $i++)
{
	$row = weight_rand($prize_arr);
	if(array_key_exists($row[&#39;prize&#39;], $result))
	{
		$result[$row[&#39;prize&#39;]] ++;
	}else{
		$result[$row[&#39;prize&#39;]] = 1;
	}
}
$cost = time() - $start;


p($result);
p(&#39;耗费时间:&#39;.$cost.&#39;秒&#39;);
function p($var)
{
  echo "<pre class="brush:php;toolbar:false">";
  if($var === false)
  {
    echo &#39;false&#39;;
  }else if($var === &#39;&#39;){
    print_r("&#39;&#39;");
  }else{
    print_r($var);
  }
  echo "
"; }

Wenn die PHP-Version nur den Ganzzahlverhältnismodus verwendet, müssen Sie die Verstärkung von Zahlen und den Algorithmus zum Finden des kleinsten gemeinsamen Vielfachen nicht berücksichtigen Es ist nur eine einfache Akkumulation erforderlich. Die Ausführungszeit kann erheblich verkürzt werden.

Das obige ist der detaillierte Inhalt vonEinführung in die Gewichtswahrscheinlichkeitszuordnungsmethode des js-Arrays. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn