2012-05-11 101 views
3

假設我想choose隨機數爲1-10,但每個數字都有權重。PHP選擇隨機數與權重

1 - 15% chance 
2 - 15% chance 
3 - 12% chance 
4 - 12% chance 
5 - 10% chance 
6 - 10% chance 
7 - 8% chance 
8 - 8% chance 
9 - 5% chance 
10 - 5% chance 

我該如何編碼PHP

+0

你可以在1使用標準的分佈(高斯)算法,平均,但ChristopheD的答案要簡單得多。 – Vulcan

回答

4

我假設你的百分比合計爲100%?

建立與

15 times a '1' value, 
15 times a '2' value, 
... 
10 times a '6' value, 
8 times a '7' value, 
... 
5 times 1 '10' value 

陣列你會與含有100種元素的單個陣列中結束。

隨機挑選一個元素(並從數組中彈出)。

+0

是否有數學方法來做到這一點,但沒有數組開銷?我們如何編碼1-100,000的東西。如果你需要的0.5%用於稱重的分辨率,而不是1%,你只需要: – Justin

+0

如果所有的權重都是整數 – Mala

+0

作出這樣的一個數組似乎過高,也不會支持類似的權重爲10.5% – Yamiko

0

將它們全部多次置於數組中,例如, 1次15次,3次12次等。 然後從該數組中選擇一個隨機數。

$array = array_merge (array_fill (0, 15, 1), array_fill (0, 15, 2), array_fill (0, 12, 3), array_fill (0, 12, 4), array_fill (0, 10, 5), array_fill (0, 10, 6), array_fill (0, 8, 7), array_fill (0, 8, 8), array_fill (0, 5, 9), array_fill (0, 5, 10)); 
$random_number = array_rand ($array); 
1

如果你的權重百分比,挑0和100之間的隨機數,然後直到你過反覆減去百分比爲零:

<?php 
function getWeightedRandom() { 
    $weights = array(15, 15, 12, ...); // these should add up to 100 
    $r = rand(0, 99); 
    for ($i=0; $i<count($weights); $i++) { 
     $r -= $weights[$i]; 
     if ($r < 0) 
      return $i+1; 
    } 
} 
?> 

這具有支持非整數的額外好處權重。

+0

如果值的權重相等,則不起作用,將$權重想象爲10次數組10.您總是會得到第一個值。還取決於$權重進行排序(降序)。 – ccKep

+0

實際上的確具有相等加權值工作,$權重並不需要進行排序(範圍[0 - 0.2]是完全可能象範圍[0.8 - 1])... – Mala

+0

是的,但您返回的第一個值符合$ r <0。想象一下'$ weights = array(1,90,9);'。你的循環迭代1作爲第一個元素,並且只有2%的機會返回** NOT **。 ($ r = 0或$ r = 1)(例如在本例中,有98%的時間你有鑰匙時有1%的概率) – ccKep

1

示例呼應使用OPS重量值與以下類:

echo 1+Rand::get_weighted_rand(array(15,15,12,12,10,10,8,8,5,5));

和類:

class Rand 
{ 
    /* 
    * generates a random value based on weight 
    * @RETURN MIXED: returns the key of an array element 
    * @PARAM $a ARRAY: 
    * the array key is the value returned and the array value is the weight 
    *  if the values sum up to less than 100 than the last element of the array 
    *  is the default value when the number is out of the range of other values 
    * @PARAM $p INT: number of digits after decimal 
    * 
    * i.e array(1=>20, 'foo'=>80): has an 80 chance of returning Foo 
    * i.e array('bar'=>0.5, 2=>1, 'default'=>0), 1: 98.5% chance of returning default 
    */ 
    public static function get_weighted_rand($a, $p=0) 
    { 
     if(array_sum($a)>100) 
      return FALSE;#total must be less than 100 
     $p=pow(10, $p+2); 
     $n=mt_rand(1,$p)*(100/$p); 
     $range=100; 
     foreach($a as $k=>$v) 
     { 
      $range-=$v; 
      if($n>$range) 
       return $k; 
     } 
      #returning default value 
     end($a); 
     return key($a); 
    } 
}