1. Repeted Werte
Nehmen wir an, wir ein Array haben, in dem jeder Wert auf die relative Wahrscheinlichkeit seines Index entspricht. Zum Beispiel, bei einer Münze, sind die möglichen Ergebnisse eines Tosses 50% Tails und 50% Heads. Wir können diese Wahrscheinlichkeit mit einer Reihe darstellen, wie (ich PHP verwenden werden, da dies die Sprache, die von OP verwendet scheint):
$dice = array('2' => 1, '3' => 2, '4' => 3, '5' => 4, '6' => 5, '7' => 6,
'8' => 5, '9' => 4, '10' => 3, '11' => 2, '12' => 1
);
:
$coin = array(
'head' => 1,
'tails' => 1
);
Während die Ergebnisse von zwei Würfeln können dargestellt werden als
Ein einfacher Weg, um einen zufälligen Schlüssel (Index) mit einer Wahrscheinlichkeit proportional zu den Werten dieser Arrays (und damit konsistent zum zugrunde liegenden Modell) auszuwählen, ist ein anderes Array zu erstellen, dessen Elemente die Schlüssel des ursprünglichen so oft wiederholen wie durch die Werte angezeigt und dann einen zufälligen Wert zurückgeben. Zum Beispiel für die dice
Array:
$arr = array(2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, ...
Dabei sind wir davon überzeugt, dass jede Taste mit der rechten relativen Wahrscheinlichkeit abgeholt werden. Wir können mit einem constructer in einer Klasse die gesamte Logik kapseln, die die Helfer Array eine Funktion erstellt, die einen zufälligen Index mt_rand() mit zurückgibt:
class RandomKeyMultiple {
private $pool = array();
private $max_range;
function __construct($source) {
// build the look-up array
foreach ($source as $key => $value) {
for ($i = 0; $i < $value; $i++) {
$this->pool[] = $key;
}
}
$this->max_range = count($this->pool) - 1;
}
function get_random_key() {
$x = mt_rand(0, $this->max_range);
return $this->pool[$x];
}
}
Die Nutzung ist einfach, erstellen Sie einfach ein Objekt der Klasse der Quelle vorbei Array und dann wird jeder Aufruf der Funktion wird einen zufälligen Schlüssel zurück:
$test = new RandomKeyMultiple($dice);
echo $test->get_random_key();
Das Problem ist, dass OP der Arrays großen Wert enthält, und dies führt zu einem sehr groß (aber immer noch überschaubar, auch ohne alle Werte von 100 dividiert) Array.
2. Schritte
Im Allgemeinen können diskrete Wahrscheinlichkeitsverteilung komplizierter sein, mit Float-Werte, die nicht leicht in der Anzahl der Wiederholungen übersetzt werden kann.
Eine andere Möglichkeit, das Problem zu lösen ist, die Werte im Array als die misures von Intervallen zu prüfen, die die globale Reichweite aller möglichen Werte teilen:
+---------------------------+-----------------+-------+----+
| | | | |
|<--- 265000 --->|<-- 190000 -->|<30000>|1300|
|<------- 455000 ------>| |
|<---------- 485000 --------->| |
|<---------------- 486300 -------------->|
Dann können wir eine Zufallszahl zwischen 0 wählen und 486300 (der globale Bereich) und den richtigen Index nachschlagen (dessen Chancen proportional zur Länge seines Segments wären, was die richtige Wahrscheinlichkeitsverteilung ergibt).Etwas wie:
$x = mt_rand(0, 486300);
if ($x < 265000)
return 0;
elseif ($x < 455000)
return 1;
elseif ($x < 485000)
return 2;
else
return 3;
Wir haben den Algorithmus verallgemeinern kann und kapseln die gesamte Logik in einer Klasse (ein Helfer Array mit den Teilsummen speichern):
class RandomKey {
private $steps = array();
private $last_key;
private $max_range;
function __construct($source) {
// sort in ascending order to partially avoid numerical issues
asort($source);
// calculate the partial sums. Considering OP's array:
//
// 1300 ----> 0
// 30000 ----> 1300
// 190000 ----> 31300
// 265000 ----> 221300 endind with $partial = 486300
//
$partial = 0;
$temp = 0;
foreach ($source as $k => &$v) {
$temp = $v;
$v = $partial;
$partial += $temp;
}
// scale the steps to cover the entire mt_rand() range
$factor = mt_getrandmax()/$partial;
foreach ($source as $k => &$v) {
$v *= $factor;
}
// Having the most probably outcomes first, minimizes the look-up of
// the correct index
$this->steps = array_reverse($source);
// remove last element (don't needed during checks) but save the key
end($this->steps);
$this->last_key = key($this->steps);
array_pop($this->steps);
}
function get_random_key() {
$x = mt_rand();
foreach ($this->steps as $key => $value) {
if ($x > $value) {
return $key;
}
}
return $this->last_key;
}
}
Here oder here gibt es Live-Demos mit einige Beispiele und Hilfsfunktionen, um die Wahrscheinlichkeitsverteilung der Schlüssel zu überprüfen.
Bei größeren Arrays kann auch eine binäre Suche zur Suche nach dem Index in Betracht gezogen werden.
Was bedeutet „bezogen auf die Fläche“ verstehen? Es ist nicht wirklich klar, was Sie hier versuchen wollen. –
Werden diese Werte zufällig gewichtet? Was bedeutet, dass das Array den Index '0' 265000 Mal für alle 1300 Mal auswählen soll, wählt es Index '3'? –
Vielleicht. Danke für die Antwort. – user889349